OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / libs / utils / pathlisteditor.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
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.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "pathlisteditor.h"
35
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>
46
47 #include <QtCore/QSignalMapper>
48 #include <QtCore/QMimeData>
49 #include <QtCore/QSharedPointer>
50 #include <QtCore/QDir>
51 #include <QtCore/QDebug>
52
53 namespace Utils {
54
55 // ------------ PathListPlainTextEdit:
56 // Replaces the platform separator ';',':' by '\n'
57 // when inserting, allowing for pasting in paths
58 // from the terminal or such.
59
60 class PathListPlainTextEdit : public QPlainTextEdit {
61 public:
62     explicit PathListPlainTextEdit(QWidget *parent = 0);
63 protected:
64     virtual void insertFromMimeData (const QMimeData *source);
65 };
66
67 PathListPlainTextEdit::PathListPlainTextEdit(QWidget *parent) :
68     QPlainTextEdit(parent)
69 {
70     // No wrapping, scroll at all events
71     setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
72     setLineWrapMode(QPlainTextEdit::NoWrap);
73 }
74
75 void PathListPlainTextEdit::insertFromMimeData(const QMimeData *source)
76 {
77     if (source->hasText()) {
78         // replace separator
79         QString text = source->text().trimmed();
80         text.replace(PathListEditor::separator(), QLatin1Char('\n'));
81         QSharedPointer<QMimeData> fixed(new QMimeData);
82         fixed->setText(text);
83         QPlainTextEdit::insertFromMimeData(fixed.data());
84     } else {
85         QPlainTextEdit::insertFromMimeData(source);
86     }
87 }
88
89 // ------------ PathListEditorPrivate
90 struct PathListEditorPrivate {
91     PathListEditorPrivate();
92
93     QHBoxLayout *layout;
94     QVBoxLayout *buttonLayout;
95     QToolButton *toolButton;
96     QMenu *buttonMenu;
97     QPlainTextEdit *edit;
98     QSignalMapper *envVarMapper;
99     QString fileDialogTitle;
100 };
101
102 PathListEditorPrivate::PathListEditorPrivate()   :
103         layout(new QHBoxLayout),
104         buttonLayout(new QVBoxLayout),
105         toolButton(new QToolButton),
106         buttonMenu(new QMenu),
107         edit(new PathListPlainTextEdit),
108         envVarMapper(0)
109 {
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);
115 }
116
117 PathListEditor::PathListEditor(QWidget *parent) :
118         QWidget(parent),
119         m_d(new PathListEditorPrivate)
120 {
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()));
126
127     addAction(tr("Add..."), this, SLOT(slotAdd()));
128     addAction(tr("Delete Line"), this, SLOT(deletePathAtCursor()));
129     addAction(tr("Clear"), this, SLOT(clear()));
130 }
131
132 PathListEditor::~PathListEditor()
133 {
134     delete m_d;
135 }
136
137 static inline QAction *createAction(QObject *parent, const QString &text, QObject * receiver, const char *slotFunc)
138 {
139     QAction *rc = new QAction(text, parent);
140     QObject::connect(rc, SIGNAL(triggered()), receiver, slotFunc);
141     return rc;
142 }
143
144 QAction *PathListEditor::addAction(const QString &text, QObject * receiver, const char *slotFunc)
145 {
146     QAction *rc = createAction(this, text, receiver, slotFunc);
147     m_d->buttonMenu->addAction(rc);
148     return rc;
149 }
150
151 QAction *PathListEditor::insertAction(int index /* -1 */, const QString &text, QObject * receiver, const char *slotFunc)
152 {
153     // Find the 'before' action
154     QAction *beforeAction = 0;
155     if (index >= 0) {
156         const QList<QAction*> actions = m_d->buttonMenu->actions();
157         if (index < actions.size())
158             beforeAction = actions.at(index);
159     }
160     QAction *rc = createAction(this, text, receiver, slotFunc);
161     if (beforeAction) {
162         m_d->buttonMenu->insertAction(beforeAction, rc);
163     } else {
164         m_d->buttonMenu->addAction(rc);
165     }
166     return rc;
167 }
168
169 int PathListEditor::lastAddActionIndex()
170 {
171     return 0; // Insert/Add
172 }
173
174 QString PathListEditor::pathListString() const
175 {
176     return pathList().join(separator());
177 }
178
179 QStringList PathListEditor::pathList() const
180 {
181     const QString text = m_d->edit->toPlainText().trimmed();
182     if (text.isEmpty())
183         return QStringList();
184     // trim each line
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)
188         *it = it->trimmed();
189     return rc;
190 }
191
192 void PathListEditor::setPathList(const QStringList &l)
193 {
194     m_d->edit->setPlainText(l.join(QString(QLatin1Char('\n'))));
195 }
196
197 void PathListEditor::setPathList(const QString &pathString)
198 {
199     if (pathString.isEmpty()) {
200         clear();
201     } else {
202         setPathList(pathString.split(separator(), QString::SkipEmptyParts));
203     }
204 }
205
206 void PathListEditor::setPathListFromEnvVariable(const QString &var)
207 {
208     setPathList(qgetenv(var.toLocal8Bit()));
209 }
210
211 QString PathListEditor::fileDialogTitle() const
212 {
213     return m_d->fileDialogTitle;
214 }
215
216 void PathListEditor::setFileDialogTitle(const QString &l)
217 {
218     m_d->fileDialogTitle = l;
219 }
220
221 void PathListEditor::clear()
222 {
223     m_d->edit->clear();
224 }
225
226 void PathListEditor::slotAdd()
227 {
228     const QString dir = QFileDialog::getExistingDirectory(this, m_d->fileDialogTitle);
229     if (!dir.isEmpty())
230         appendPath(QDir::toNativeSeparators(dir));
231 }
232
233 void PathListEditor::slotInsert()
234 {
235     const QString dir = QFileDialog::getExistingDirectory(this, m_d->fileDialogTitle);
236     if (!dir.isEmpty())
237         insertPathAtCursor(QDir::toNativeSeparators(dir));
238 }
239
240 QChar PathListEditor::separator()
241 {
242 #ifdef Q_OS_WIN
243     static const QChar rc(QLatin1Char(';'));
244 #else
245     static const QChar rc(QLatin1Char(':'));
246 #endif
247     return rc;
248 }
249
250 // Add a button "Import from 'Path'"
251 void PathListEditor::addEnvVariableImportAction(const QString &var)
252 {
253     if (!m_d->envVarMapper) {
254         m_d->envVarMapper = new QSignalMapper(this);
255         connect(m_d->envVarMapper, SIGNAL(mapped(QString)), this, SLOT(setPathListFromEnvVariable(QString)));
256     }
257
258     QAction *a = insertAction(lastAddActionIndex() + 1,
259                               tr("From \"%1\"").arg(var), m_d->envVarMapper, SLOT(map()));
260     m_d->envVarMapper->setMapping(a, var);
261 }
262
263 QString PathListEditor::text() const
264 {
265     return m_d->edit->toPlainText();
266 }
267
268 void PathListEditor::setText(const QString &t)
269 {
270     m_d->edit->setPlainText(t);
271 }
272
273 void PathListEditor::insertPathAtCursor(const QString &path)
274 {
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();
280     if (needNewLine) {
281         cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
282         cursor.insertBlock();
283         cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor);
284     }
285     cursor.insertText(path);
286     if (needNewLine) {
287         cursor.movePosition(QTextCursor::StartOfLine, QTextCursor::MoveAnchor);
288         m_d->edit->setTextCursor(cursor);
289     }
290 }
291
292 void PathListEditor::appendPath(const QString &path)
293 {
294     QString paths = text().trimmed();
295     if (!paths.isEmpty())
296         paths += QLatin1Char('\n');
297     paths += path;
298     setText(paths);
299 }
300
301 void PathListEditor::deletePathAtCursor()
302 {
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);
312     }
313 }
314
315 } // namespace Utils