OSDN Git Service

4252f58e87ed10e08f4ee7f09d77fc3359c47daf
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / designercore / pluginmanager / widgetpluginpath.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 "widgetpluginpath.h"
35 #include <iwidgetplugin.h>
36 #include <QtCore/QLibrary>
37 #include <QWeakPointer>
38 #include <QtCore/QPluginLoader>
39 #include <QtCore/QFileInfo>
40 #include <QtCore/QLibraryInfo>
41 #include <QtCore/QCoreApplication>
42 #include <QtCore/QObject>
43 #include <QtCore/QSharedData>
44 #include <QDebug>
45
46 enum { debug = 0 };
47
48 namespace QmlDesigner {
49
50 namespace Internal {
51
52 // Initialize and create instance of a plugin from scratch,
53 // that is, make sure the library is loaded and has an instance
54 // of the IPlugin type. Once something fails, mark it as failed
55 // ignore it from then on.
56 static IWidgetPlugin *instance(WidgetPluginData &p)
57 {
58     if (debug)
59         qDebug() << "Loading QmlDesigner plugin" << p.path << "...";
60
61     // Go stale once something fails
62     if (p.failed)
63         return 0;
64
65     // Pull up the plugin, retrieve IPlugin instance.
66     if (!p.instanceGuard) {
67         p.instance = 0;
68         QPluginLoader loader(p.path);
69
70         if (debug)
71             qDebug() << "guard" << p.path;
72
73         if (!(loader.isLoaded() || loader.load())) {
74             p.failed = true;
75             p.errorMessage = QCoreApplication::translate("WidgetPluginManager",
76                                                          "Failed to create instance of file "
77                                                          "'%1': %2").arg(p.path).arg(p.errorMessage);
78             qWarning() << p.errorMessage;
79             return 0;
80         }
81         QObject *object = loader.instance();
82         if (!object) {
83             p.failed = true;
84             p.errorMessage = QCoreApplication::translate("WidgetPluginManager",
85                                                          "Failed to create instance of file '%1'."
86                                                          ).arg(p.path);
87             qWarning() << p.errorMessage;
88             return 0;
89         }
90         IWidgetPlugin *iplugin = qobject_cast<IWidgetPlugin *>(object);
91         if (!iplugin) {
92             p.failed = true;
93             p.errorMessage = QCoreApplication::translate("WidgetPluginManager",
94                                                          "File '%1' is not a QmlDesigner plugin."
95                                                          ).arg(p.path);
96             qWarning() << p.errorMessage;
97             delete object;
98             return 0;
99         }
100         p.instanceGuard = object;
101         p.instance = iplugin;
102     }
103     // Ensure it is initialized
104     /*if (!p.instance->isInitialized()) {
105         if (!p.instance->initialize(&p.errorMessage)) {
106             p.failed = true;
107             delete p.instance;
108             p.instance = 0;
109             return 0;
110         }
111     }*/
112
113     if (debug)
114         qDebug() << "QmlDesigner plugin" << p.path << "successfully loaded!";
115     return p.instance;
116 }
117
118 WidgetPluginData::WidgetPluginData(const QString &p) :
119     path(p),
120     failed(false),
121     instance(0)
122 {
123 }
124
125
126 WidgetPluginPath::WidgetPluginPath(const QDir &path) :
127     m_path(path),
128     m_loaded(false)
129 {
130 }
131
132 // Determine a unique list of library files in that directory
133 QStringList WidgetPluginPath::libraryFilePaths(const QDir &dir)
134 {
135     const QFileInfoList infoList = dir.entryInfoList(QDir::Files|QDir::Readable|QDir::NoDotAndDotDot);
136     if (infoList.empty())
137         return QStringList();
138       // Load symbolic links but make sure all file names are unique as not
139     // to fall for something like 'libplugin.so.1 -> libplugin.so'
140     QStringList result;
141     const QFileInfoList::const_iterator icend = infoList.constEnd();
142     for (QFileInfoList::const_iterator it = infoList.constBegin(); it != icend; ++it) {
143         QString fileName;
144         if (it->isSymLink()) {
145             const QFileInfo linkTarget = QFileInfo(it->symLinkTarget());
146             if (linkTarget.exists() && linkTarget.isFile())
147                 fileName = linkTarget.absoluteFilePath();
148         } else {
149             fileName = it->absoluteFilePath();
150         }
151         if (!fileName.isEmpty() && QLibrary::isLibrary(fileName) && !result.contains(fileName))
152             result += fileName;
153     }
154
155     if (debug)
156         qDebug() << "Library files in directory" << dir << ": " << result;
157
158     return result;
159 }
160
161 void WidgetPluginPath::clear()
162 {
163     m_loaded = false;
164     m_plugins.clear();
165 }
166
167 void WidgetPluginPath::ensureLoaded()
168 {
169     if (!m_loaded) {
170         const QStringList libraryFiles = libraryFilePaths(m_path);
171         if (debug)
172             qDebug() << "Checking " << libraryFiles.size() << " plugins " << m_path.absolutePath();
173         foreach (const QString &libFile, libraryFiles)
174             m_plugins.push_back(WidgetPluginData(libFile));
175         m_loaded = true;
176     }
177 }
178
179 void WidgetPluginPath::getInstances(WidgetPluginManager::IWidgetPluginList *list)
180 {
181     ensureLoaded();
182     // Compile list of instances
183     if (m_plugins.empty())
184         return;
185     const PluginDataList::iterator end = m_plugins.end();
186     for (PluginDataList::iterator it = m_plugins.begin(); it != end; ++it)
187         if (IWidgetPlugin *i = instance(*it))
188             list->push_back(i);
189 }
190
191 QStandardItem *WidgetPluginPath::createModelItem()
192 {
193     ensureLoaded();
194     // Create a list of plugin lib files with classes.
195     // If there are failed ones, create a separate "Failed"
196     // category at the end
197     QStandardItem *pathItem = new QStandardItem(m_path.absolutePath());
198     QStandardItem *failedCategory = 0;
199     const PluginDataList::iterator end = m_plugins.end();
200     for (PluginDataList::iterator it = m_plugins.begin(); it != end; ++it) {
201         QStandardItem *pluginItem = new QStandardItem(QFileInfo(it->path).fileName());
202         if (instance(*it)) {
203             pluginItem->appendRow(new QStandardItem(QString::fromLatin1(it->instanceGuard->metaObject()->className())));
204             pathItem->appendRow(pluginItem);
205         } else {
206             pluginItem->setToolTip(it->errorMessage);
207             if (!failedCategory) {
208                 const QString failed = QCoreApplication::translate("PluginManager", "Failed Plugins");
209                 failedCategory = new QStandardItem(failed);
210             }
211             failedCategory->appendRow(pluginItem);
212         }
213     }
214     if (failedCategory)
215         pathItem->appendRow(failedCategory);
216     return pathItem;
217 }
218
219 } // namespace Internal
220 } // namespace QmlDesigner
221