1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
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 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "pathlisteditor.h"
36 #include <QtGui/QVBoxLayout>
37 #include <QtGui/QHBoxLayout>
38 #include <QtGui/QPlainTextEdit>
39 #include <QtGui/QToolButton>
40 #include <QtGui/QSpacerItem>
41 #include <QtGui/QFileDialog>
42 #include <QtGui/QTextCursor>
43 #include <QtGui/QTextBlock>
44 #include <QtGui/QMenu>
45 #include <QtGui/QAction>
47 #include <QtCore/QSignalMapper>
48 #include <QtCore/QMimeData>
49 #include <QtCore/QSharedPointer>
50 #include <QtCore/QDir>
51 #include <QtCore/QDebug>
55 // ------------ PathListPlainTextEdit:
56 // Replaces the platform separator ';',':' by '\n'
57 // when inserting, allowing for pasting in paths
58 // from the terminal or such.
60 class PathListPlainTextEdit : public QPlainTextEdit {
62 explicit PathListPlainTextEdit(QWidget *parent = 0);
64 virtual void insertFromMimeData (const QMimeData *source);
67 PathListPlainTextEdit::PathListPlainTextEdit(QWidget *parent) :
68 QPlainTextEdit(parent)
70 // No wrapping, scroll at all events
71 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
72 setLineWrapMode(QPlainTextEdit::NoWrap);
75 void PathListPlainTextEdit::insertFromMimeData(const QMimeData *source)
77 if (source->hasText()) {
79 QString text = source->text().trimmed();
80 text.replace(PathListEditor::separator(), QLatin1Char('\n'));
81 QSharedPointer<QMimeData> fixed(new QMimeData);
83 QPlainTextEdit::insertFromMimeData(fixed.data());
85 QPlainTextEdit::insertFromMimeData(source);
89 // ------------ PathListEditorPrivate
90 struct PathListEditorPrivate {
91 PathListEditorPrivate();
94 QVBoxLayout *buttonLayout;
95 QToolButton *toolButton;
98 QSignalMapper *envVarMapper;
99 QString fileDialogTitle;
102 PathListEditorPrivate::PathListEditorPrivate() :
103 layout(new QHBoxLayout),
104 buttonLayout(new QVBoxLayout),
105 toolButton(new QToolButton),
106 buttonMenu(new QMenu),
107 edit(new PathListPlainTextEdit),
110 layout->setMargin(0);
111 layout->addWidget(edit);
112 buttonLayout->addWidget(toolButton);
113 buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding));
114 layout->addLayout(buttonLayout);
117 PathListEditor::PathListEditor(QWidget *parent) :
119 m_d(new PathListEditorPrivate)
121 setLayout(m_d->layout);
122 m_d->toolButton->setPopupMode(QToolButton::MenuButtonPopup);
123 m_d->toolButton->setText(tr("Insert..."));
124 m_d->toolButton->setMenu(m_d->buttonMenu);
125 connect(m_d->toolButton, SIGNAL(clicked()), this, SLOT(slotInsert()));
127 addAction(tr("Add..."), this, SLOT(slotAdd()));
128 addAction(tr("Delete Line"), this, SLOT(deletePathAtCursor()));
129 addAction(tr("Clear"), this, SLOT(clear()));
132 PathListEditor::~PathListEditor()
137 static inline QAction *createAction(QObject *parent, const QString &text, QObject * receiver, const char *slotFunc)
139 QAction *rc = new QAction(text, parent);
140 QObject::connect(rc, SIGNAL(triggered()), receiver, slotFunc);
144 QAction *PathListEditor::addAction(const QString &text, QObject * receiver, const char *slotFunc)
146 QAction *rc = createAction(this, text, receiver, slotFunc);
147 m_d->buttonMenu->addAction(rc);
151 QAction *PathListEditor::insertAction(int index /* -1 */, const QString &text, QObject * receiver, const char *slotFunc)
153 // Find the 'before' action
154 QAction *beforeAction = 0;
156 const QList<QAction*> actions = m_d->buttonMenu->actions();
157 if (index < actions.size())
158 beforeAction = actions.at(index);
160 QAction *rc = createAction(this, text, receiver, slotFunc);
162 m_d->buttonMenu->insertAction(beforeAction, rc);
164 m_d->buttonMenu->addAction(rc);
169 int PathListEditor::lastAddActionIndex()
171 return 0; // Insert/Add
174 QString PathListEditor::pathListString() const
176 return pathList().join(separator());
179 QStringList PathListEditor::pathList() const
181 const QString text = m_d->edit->toPlainText().trimmed();
183 return QStringList();
185 QStringList rc = text.split(QLatin1Char('\n'), QString::SkipEmptyParts);
186 const QStringList::iterator end = rc.end();
187 for (QStringList::iterator it = rc.begin(); it != end; ++it)
192 void PathListEditor::setPathList(const QStringList &l)
194 m_d->edit->setPlainText(l.join(QString(QLatin1Char('\n'))));
197 void PathListEditor::setPathList(const QString &pathString)
199 if (pathString.isEmpty()) {
202 setPathList(pathString.split(separator(), QString::SkipEmptyParts));
206 void PathListEditor::setPathListFromEnvVariable(const QString &var)
208 setPathList(qgetenv(var.toLocal8Bit()));
211 QString PathListEditor::fileDialogTitle() const
213 return m_d->fileDialogTitle;
216 void PathListEditor::setFileDialogTitle(const QString &l)
218 m_d->fileDialogTitle = l;
221 void PathListEditor::clear()
226 void PathListEditor::slotAdd()
228 const QString dir = QFileDialog::getExistingDirectory(this, m_d->fileDialogTitle);
230 appendPath(QDir::toNativeSeparators(dir));
233 void PathListEditor::slotInsert()
235 const QString dir = QFileDialog::getExistingDirectory(this, m_d->fileDialogTitle);
237 insertPathAtCursor(QDir::toNativeSeparators(dir));
240 QChar PathListEditor::separator()
243 static const QChar rc(QLatin1Char(';'));
245 static const QChar rc(QLatin1Char(':'));
250 // Add a button "Import from 'Path'"
251 void PathListEditor::addEnvVariableImportAction(const QString &var)
253 if (!m_d->envVarMapper) {
254 m_d->envVarMapper = new QSignalMapper(this);
255 connect(m_d->envVarMapper, SIGNAL(mapped(QString)), this, SLOT(setPathListFromEnvVariable(QString)));
258 QAction *a = insertAction(lastAddActionIndex() + 1,
259 tr("From \"%1\"").arg(var), m_d->envVarMapper, SLOT(map()));
260 m_d->envVarMapper->setMapping(a, var);
263 QString PathListEditor::text() const
265 return m_d->edit->toPlainText();
268 void PathListEditor::setText(const QString &t)
270 m_d->edit->setPlainText(t);
273 void PathListEditor::insertPathAtCursor(const QString &path)
275 // If the cursor is at an empty line or at end(),
276 // just insert. Else insert line before
277 QTextCursor cursor = m_d->edit->textCursor();
278 QTextBlock block = cursor.block();
279 const bool needNewLine = !block.text().isEmpty();
281 cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
282 cursor.insertBlock();
283 cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor);
285 cursor.insertText(path);
287 cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
288 m_d->edit->setTextCursor(cursor);
292 void PathListEditor::appendPath(const QString &path)
294 QString paths = text().trimmed();
295 if (!paths.isEmpty())
296 paths += QLatin1Char('\n');
301 void PathListEditor::deletePathAtCursor()
303 // Delete current line
304 QTextCursor cursor = m_d->edit->textCursor();
305 if (cursor.block().isValid()) {
306 cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
307 // Select down or until end of [last] line
308 if (!cursor.movePosition(QTextCursor::Down, QTextCursor::KeepAnchor))
309 cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
310 cursor.removeSelectedText();
311 m_d->edit->setTextCursor(cursor);