1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
28 **************************************************************************/
30 #include "gettingstartedwelcomepagewidget.h"
31 #include "ui_gettingstartedwelcomepagewidget.h"
33 #include <coreplugin/icore.h>
34 #include <coreplugin/helpmanager.h>
35 #include <coreplugin/coreconstants.h>
36 #include <coreplugin/mainwindow.h>
37 #include <projectexplorer/projectexplorer.h>
39 #include <utils/pathchooser.h>
41 #include <extensionsystem/pluginmanager.h>
43 #include <QtCore/QDateTime>
44 #include <QtCore/QDir>
45 #include <QtCore/QFileInfo>
46 #include <QtCore/QDebug>
47 #include <QtCore/QStringBuilder>
48 #include <QtCore/QUrl>
49 #include <QtCore/QTimer>
50 #include <QtCore/QSettings>
51 #include <QtCore/QXmlStreamReader>
52 #include <QtGui/QDialogButtonBox>
53 #include <QtGui/QFont>
54 #include <QtGui/QMessageBox>
55 #include <QtGui/QPushButton>
56 #include <QtGui/QMenu>
58 namespace Qt4ProjectManager {
61 const char ExamplePathPropertyName[] = "__qt_ExamplePath";
62 const char HelpPathPropertyName[] = "__qt_HelpPath";
64 GettingStartedWelcomePageWidget::GettingStartedWelcomePageWidget(QWidget *parent) :
66 ui(new Ui::GettingStartedWelcomePageWidget)
70 ui->didYouKnowTextBrowser->viewport()->setAutoFillBackground(false);
72 connect(ui->tutorialTreeWidget, SIGNAL(activated(QString)), SLOT(slotOpenHelpPage(const QString&)));
74 ui->tutorialTreeWidget->addItem(tr("The Qt Creator User Interface"),
75 QLatin1String("qthelp://com.nokia.qtcreator/doc/creator-quick-tour.html"));
76 ui->tutorialTreeWidget->addItem(tr("Building and Running an Example"),
77 QLatin1String("qthelp://com.nokia.qtcreator/doc/creator-build-example-application.html?view=split"));
78 ui->tutorialTreeWidget->addItem(tr("Creating a Qt C++ Application"),
79 QLatin1String("qthelp://com.nokia.qtcreator/doc/creator-writing-program.html?view=split"));
80 ui->tutorialTreeWidget->addItem(tr("Creating a Mobile Application"),
81 QLatin1String("qthelp://com.nokia.qtcreator/doc/creator-mobile-example.html?view=split"));
82 ui->tutorialTreeWidget->addItem(tr("Creating a Qt Quick Application"),
83 QLatin1String("qthelp://com.nokia.qtcreator/doc/creator-qml-application.html?view=split"));
85 srand(QDateTime::currentDateTime().toTime_t());
86 QStringList tips = tipsOfTheDay();
87 m_currentTip = rand()%tips.count();
89 QTextDocument *doc = ui->didYouKnowTextBrowser->document();
90 doc->setDefaultStyleSheet("a:link {color:black;}");
91 ui->didYouKnowTextBrowser->setDocument(doc);
92 ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));
94 connect(ui->nextTipBtn, SIGNAL(clicked()), this, SLOT(slotNextTip()));
95 connect(ui->prevTipBtn, SIGNAL(clicked()), this, SLOT(slotPrevTip()));
96 connect(ui->openProjectButton, SIGNAL(clicked()),
97 ProjectExplorer::ProjectExplorerPlugin::instance(),
98 SLOT(openOpenProjectDialog()));
99 connect(ui->createNewProjectButton, SIGNAL(clicked()), this, SLOT(slotCreateNewProject()));
101 ui->createNewProjectButton->setIcon(
102 QIcon::fromTheme(QLatin1String("document-new"), ui->createNewProjectButton->icon()));
103 ui->openProjectButton->setIcon(
104 QIcon::fromTheme(QLatin1String("document-open"), ui->openProjectButton->icon()));
105 QTimer::singleShot(0, this, SLOT(slotSetPrivateQmlExamples()));
108 GettingStartedWelcomePageWidget::~GettingStartedWelcomePageWidget()
113 void GettingStartedWelcomePageWidget::slotSetPrivateQmlExamples()
115 if (!ui->qmlExamplesButton->menu()) {
116 const QString resPath = Core::ICore::instance()->resourcePath();
117 updateQmlExamples(resPath, resPath);
121 void GettingStartedWelcomePageWidget::updateCppExamples(const QString &examplePath,
122 const QString &sourcePath,
123 const QString &demoXml)
126 QFile description(demoXml);
127 if (!description.open(QFile::ReadOnly))
130 ui->cppExamplesButton->setEnabled(true);;
131 ui->cppExamplesButton->setText(tr("Choose an example..."));
133 QMenu *menu = new QMenu(ui->cppExamplesButton);
134 ui->cppExamplesButton->setMenu(menu);
137 bool inExamples = false;
139 QXmlStreamReader reader(&description);
141 while (!reader.atEnd()) {
142 switch (reader.readNext()) {
143 case QXmlStreamReader::StartElement:
144 if (reader.name() == QLatin1String("category")) {
145 QString name = reader.attributes().value(QLatin1String("name")).toString();
146 if (name.contains(QLatin1String("tutorial")))
148 dirName = reader.attributes().value(QLatin1String("dirname")).toString();
149 subMenu = menu->addMenu(name);
152 if (inExamples && reader.name() == QLatin1String("example")) {
153 const QChar slash = QLatin1Char('/');
154 const QString name = reader.attributes().value(QLatin1String("name")).toString();
155 const QString fn = reader.attributes().value(QLatin1String("filename")).toString();
156 const QString relativeProPath = slash + dirName + slash + fn + slash + fn + QLatin1String(".pro");
157 QString fileName = examplePath + relativeProPath;
158 if (!QFile::exists(fileName))
159 fileName = sourcePath + QLatin1String("/examples") + relativeProPath;
160 QString dirName1 = dirName;
161 dirName1.replace(slash, QLatin1Char('-'));
162 QString helpPath = QLatin1String("qthelp://com.trolltech.qt/qdoc/") +
164 QLatin1Char('-') + fn + QLatin1String(".html");
166 QAction *exampleAction = subMenu->addAction(name);
167 connect(exampleAction, SIGNAL(triggered()), SLOT(slotOpenExample()));
169 exampleAction->setProperty(ExamplePathPropertyName, fileName);
170 exampleAction->setProperty(HelpPathPropertyName, helpPath);
173 case QXmlStreamReader::EndElement:
174 if (reader.name() == QLatin1String("category"))
183 void GettingStartedWelcomePageWidget::updateQmlExamples(const QString &examplePath,
184 const QString &sourcePath)
186 ui->qmlExamplesButton->setText(tr("Choose an example..."));
189 roots << (examplePath + QLatin1String("/declarative"))
190 << (sourcePath + QLatin1String("/examples/declarative"));
191 QMap<QString, QString> exampleProjects;
193 foreach (const QString &root, roots) {
194 QList<QFileInfo> examples = QDir(root).entryInfoList(QStringList(), QDir::AllDirs|QDir::NoDotAndDotDot, QDir::Name);
195 foreach(const QFileInfo &example, examples) {
196 const QString fileName = example.fileName();
197 if (exampleProjects.contains(fileName))
199 const QString exampleProject = example.absoluteFilePath()
200 + QLatin1Char('/') + fileName
201 + QLatin1String(".qmlproject");
202 if (!QFile::exists(exampleProject))
204 exampleProjects.insert(fileName, exampleProject);
208 if (!exampleProjects.isEmpty()) {
209 QMenu *menu = new QMenu(ui->qmlExamplesButton);
210 ui->qmlExamplesButton->setMenu(menu);
212 QMapIterator<QString, QString> it(exampleProjects);
213 while (it.hasNext()) {
215 QAction *exampleAction = menu->addAction(it.key());
216 connect(exampleAction, SIGNAL(triggered()), SLOT(slotOpenExample()));
217 exampleAction->setProperty(ExamplePathPropertyName, it.value());
218 // FIXME once we have help for QML examples
219 // exampleAction->setProperty(HelpPathPropertyName, helpPath);
223 ui->qmlExamplesButton->setEnabled(!exampleProjects.isEmpty());
226 void GettingStartedWelcomePageWidget::updateExamples(const QString &examplePath,
227 const QString &demosPath,
228 const QString &sourcePath)
230 QString demoxml = demosPath + "/qtdemo/xml/examples.xml";
231 if (!QFile::exists(demoxml)) {
232 demoxml = sourcePath + "/demos/qtdemo/xml/examples.xml";
233 if (!QFile::exists(demoxml))
236 updateCppExamples(examplePath, sourcePath, demoxml);
237 updateQmlExamples(examplePath, sourcePath);
242 void copyRecursive(const QDir& from, const QDir& to, const QString& dir)
249 foreach(const QFileInfo& roFile, src.entryInfoList(QDir::Files)) {
250 QFile::copy(roFile.absoluteFilePath(), dest.absolutePath() + '/' + roFile.fileName());
252 foreach(const QString& roDir, src.entryList(QDir::NoDotAndDotDot|QDir::Dirs)) {
253 copyRecursive(src, dest, QDir(roDir).dirName());
258 void GettingStartedWelcomePageWidget::slotOpenExample()
260 QAction *action = qobject_cast<QAction*>(sender());
264 QString helpFile = action->property(HelpPathPropertyName).toString();
265 QString proFile = action->property(ExamplePathPropertyName).toString();
268 QFileInfo proFileInfo(proFile);
269 // If the Qt is a distro Qt on Linux, it will not be writable, hence compilation will fail
270 if (!proFileInfo.isWritable())
273 QGridLayout *lay = new QGridLayout(&d);
274 QLabel *descrLbl = new QLabel;
275 d.setWindowTitle(tr("Copy Project to writable Location?"));
276 descrLbl->setTextFormat(Qt::RichText);
277 descrLbl->setWordWrap(true);
278 descrLbl->setText(tr("<p>The project you are about to open is located in the "
279 "write-protected location:</p><blockquote>%1</blockquote>"
280 "<p>Please select a writable location below and click \"Copy Project and Open\" "
281 "to open a modifiable copy of the project or click \"Keep Project and Open\" "
282 "to open the project in location.</p><p><b>Note:</b> You will not "
283 "be able to alter or compile your project in the current location.</p>")
284 .arg(QDir::toNativeSeparators(proFileInfo.dir().absolutePath())));
285 lay->addWidget(descrLbl, 0, 0, 1, 2);
286 QLabel *txt = new QLabel(tr("&Location:"));
287 Utils::PathChooser *chooser = new Utils::PathChooser;
288 txt->setBuddy(chooser);
289 chooser->setExpectedKind(Utils::PathChooser::Directory);
290 QSettings *settings = Core::ICore::instance()->settings();
291 chooser->setPath(settings->value(
292 QString::fromLatin1("General/ProjectsFallbackRoot"), QDir::homePath()).toString());
293 lay->addWidget(txt, 1, 0);
294 lay->addWidget(chooser, 1, 1);
295 QDialogButtonBox *bb = new QDialogButtonBox;
296 connect(bb, SIGNAL(accepted()), &d, SLOT(accept()));
297 connect(bb, SIGNAL(rejected()), &d, SLOT(reject()));
298 QPushButton *copyBtn = bb->addButton(tr("&Copy Project and Open"), QDialogButtonBox::AcceptRole);
299 copyBtn->setDefault(true);
300 bb->addButton(tr("&Keep Project and Open"), QDialogButtonBox::RejectRole);
301 lay->addWidget(bb, 2, 0, 1, 2);
302 connect(chooser, SIGNAL(validChanged(bool)), copyBtn, SLOT(setEnabled(bool)));
303 if (d.exec() == QDialog::Accepted) {
304 QString exampleDirName = proFileInfo.dir().dirName();
305 QString toDir = chooser->path();
306 settings->setValue(QString::fromLatin1("General/ProjectsFallbackRoot"), toDir);
307 QDir toDirWithExamplesDir(toDir);
308 if (toDirWithExamplesDir.cd(exampleDirName)) {
309 toDirWithExamplesDir.cdUp(); // step out, just to not be in the way
310 QMessageBox::warning(topLevelWidget(), tr("Warning"),
311 tr("The specified location already exists. "
312 "Please specify a valid location."),
313 QMessageBox::Ok, QMessageBox::NoButton);
316 QDir from = proFileInfo.dir();
318 copyRecursive(from, toDir, exampleDirName);
319 // set vars to new location
320 proFileInfo = QFileInfo(toDir + '/'+ exampleDirName + '/' + proFileInfo.fileName());
321 proFile = proFileInfo.absoluteFilePath();
327 QString tryFile = proFileInfo.path() + "/main.cpp";
329 if(!QFile::exists(tryFile))
330 tryFile = proFileInfo.path() + '/' + proFileInfo.baseName() + ".cpp";
331 // maybe it's a QML project?
332 if(!QFile::exists(tryFile))
333 tryFile = proFileInfo.path() + '/' + "/main.qml";
334 if(!QFile::exists(tryFile))
335 tryFile = proFileInfo.path() + '/' + proFileInfo.baseName() + ".qml";
336 if(QFile::exists(tryFile))
338 Core::ICore::instance()->openFiles(files);
339 if (!helpFile.isEmpty())
340 slotOpenContextHelpPage(helpFile);
343 void GettingStartedWelcomePageWidget::slotOpenHelpPage(const QString& url)
345 Core::HelpManager *helpManager = Core::HelpManager::instance();
346 Q_ASSERT(helpManager);
347 helpManager->handleHelpRequest(url);
349 void GettingStartedWelcomePageWidget::slotOpenContextHelpPage(const QString& url)
351 Core::HelpManager *helpManager = Core::HelpManager::instance();
352 Q_ASSERT(helpManager);
353 helpManager->handleHelpRequest(url % QLatin1String("?view=split"));
356 void GettingStartedWelcomePageWidget::slotCreateNewProject()
358 Core::ICore::instance()->showNewItemDialog(tr("New Project"),
359 Core::IWizard::wizardsOfKind(Core::IWizard::ProjectWizard));
362 void GettingStartedWelcomePageWidget::slotNextTip()
364 QStringList tips = tipsOfTheDay();
365 m_currentTip = ((m_currentTip+1)%tips.count());
366 ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));
369 void GettingStartedWelcomePageWidget::slotPrevTip()
371 QStringList tips = tipsOfTheDay();
372 m_currentTip = ((m_currentTip-1)+tips.count())%tips.count();
373 ui->didYouKnowTextBrowser->setText(tips.at(m_currentTip));
376 QStringList GettingStartedWelcomePageWidget::tipsOfTheDay()
378 static QStringList tips;
379 if (tips.isEmpty()) {
380 QString altShortcut =
382 tr("Cmd", "Shortcut key");
384 tr("Alt", "Shortcut key");
387 QString ctrlShortcut =
389 tr("Cmd", "Shortcut key");
391 tr("Ctrl", "Shortcut key");
394 //:%1 gets replaced by Alt (Win/Unix) or Cmd (Mac)
395 tips.append(tr("You can show and hide the side bar using <tt>%1+0<tt>.").arg(altShortcut));
396 tips.append(tr("You can fine tune the <tt>Find</tt> function by selecting "Whole Words" "
397 "or "Case Sensitive". Simply click on the icons on the right end of the line edit."));
398 tips.append(tr("If you add external libraries to your project, Qt Creator will automatically offer syntax highlighting "
399 "and code completion."));
400 tips.append(tr("The code completion is CamelCase-aware. For example, to complete <tt>namespaceUri</tt> "
401 "you can just type <tt>nU</tt> and hit <tt>Ctrl+Space</tt>."));
402 tips.append(tr("You can force code completion at any time using <tt>Ctrl+Space</tt>."));
403 tips.append(tr("You can start Qt Creator with a session by calling <tt>qtcreator <sessionname></tt>."));
404 tips.append(tr("You can return to edit mode from any other mode at any time by hitting <tt>Escape</tt>."));
405 //:%1 gets replaced by Alt (Win/Unix) or Cmd (Mac)
406 tips.append(tr("You can switch between the output pane by hitting <tt>%1+n</tt> where n is the number denoted "
407 "on the buttons at the window bottom:"
408 "<ul><li>1 - Build Issues</li><li>2 - Search Results</li><li>3 - Application Output</li>"
409 "<li>4 - Compile Output</li></ul>").arg(altShortcut));
410 tips.append(tr("You can quickly search methods, classes, help and more using the "
411 "<a href=\"qthelp://com.nokia.qtcreator/doc/creator-editor-locator.html\">Locator bar</a> (<tt>%1+K</tt>).").arg(ctrlShortcut));
412 tips.append(tr("You can add custom build steps in the "
413 "<a href=\"qthelp://com.nokia.qtcreator/doc/creator-build-settings.html\">build settings</a>."));
414 tips.append(tr("Within a session, you can add "
415 "<a href=\"qthelp://com.nokia.qtcreator/doc/creator-build-dependencies.html\">dependencies</a> between projects."));
416 tips.append(tr("You can set the preferred editor encoding for every project in <tt>Projects -> Editor Settings -> Default Encoding</tt>."));
417 tips.append(tr("You can use Qt Creator with a number of <a href=\"qthelp://com.nokia.qtcreator/doc/creator-version-control.html\">"
418 "revision control systems</a> such as Subversion, Perforce, CVS and Git."));
419 tips.append(tr("In the editor, <tt>F2</tt> follows symbol definition, <tt>Shift+F2</tt> toggles declaration and definition "
420 "while <tt>F4</tt> toggles header file and source file."));
426 } // namespace Internal
427 } // namespace Qt4ProjectManager