QGIS API Documentation 3.99.0-Master (e9821da5c6b)
Loading...
Searching...
No Matches
qgszipitem.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgszipitem.cpp
3 -------------------
4 begin : 2011-04-01
5 copyright : (C) 2011 Radim Blazek
6 email : radim dot blazek at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include "qgszipitem.h"
19
20#include <cpl_string.h>
21#include <cpl_vsi.h>
22#include <mutex>
23
24#include "qgsapplication.h"
25#include "qgsdataitemprovider.h"
27#include "qgsgdalutils.h"
28#include "qgssettings.h"
29
30#include <QFileInfo>
31#include <QString>
32
33#include "moc_qgszipitem.cpp"
34
35using namespace Qt::StringLiterals;
36
38{
39 return QgsApplication::getThemeIcon( u"/mIconZip.svg"_s );
40}
41
42
43//-----------------------------------------------------------------------
44QStringList QgsZipItem::sProviderNames = QStringList();
45
46
47QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString &path )
49{
51 init();
52}
53
55 const QString &filePath, const QString &path,
56 const QString &providerKey )
58 , mFilePath( filePath )
59{
60 init();
61}
62
63void QgsZipItem::init()
64{
66 mIconName = u"/mIconZip.svg"_s;
68
70
71 static std::once_flag initialized;
72 std::call_once( initialized, []
73 {
74 sProviderNames << u"files"_s;
75 } );
76}
77
79{
80 return true;
81}
82
84{
86 u.layerType = u"collection"_s;
87 u.uri = path();
88 u.filePath = path();
89 return { u };
90}
91
92QString QgsZipItem::vsiPrefix( const QString &uri )
93{
95}
96
97QVector<QgsDataItem *> QgsZipItem::createChildren()
98{
99 QVector<QgsDataItem *> children;
100 QString tmpPath;
101 const QgsSettings settings;
102 const QString scanZipSetting = settings.value( u"qgis/scanZipInBrowser2"_s, "basic" ).toString();
103
104 mZipFileList.clear();
105
106 QgsDebugMsgLevel( u"mFilePath = %1 path = %2 name= %3 scanZipSetting= %4 vsiPrefix= %5"_s.arg( mFilePath, path(), name(), scanZipSetting, mVsiPrefix ), 3 );
107
108 // if scanZipBrowser == no: skip to the next file
109 if ( scanZipSetting == "no"_L1 )
110 {
111 return children;
112 }
113
114 // first get list of files
116
117 const QList<QgsDataItemProvider *> providers = QgsApplication::dataItemProviderRegistry()->providers();
118
119 // loop over files inside zip
120 const auto constMZipFileList = mZipFileList;
121 for ( const QString &fileName : constMZipFileList )
122 {
123 const QFileInfo info( fileName );
124 tmpPath = mVsiPrefix + mFilePath + '/' + fileName;
125 QgsDebugMsgLevel( "tmpPath = " + tmpPath, 3 );
126
127 for ( QgsDataItemProvider *provider : providers )
128 {
129 if ( !sProviderNames.contains( provider->name() ) )
130 continue;
131
132 // ugly hack to remove .dbf file if there is a .shp file
133 if ( provider->name() == "OGR"_L1 )
134 {
135 if ( info.suffix().compare( "dbf"_L1, Qt::CaseInsensitive ) == 0 )
136 {
137 if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
138 continue;
139 }
140 if ( info.completeSuffix().compare( "shp.xml"_L1, Qt::CaseInsensitive ) == 0 )
141 {
142 continue;
143 }
144 }
145
146 QgsDebugMsgLevel( u"trying to load item %1 with %2"_s.arg( tmpPath, provider->name() ), 3 );
147 QgsDataItem *item = provider->createDataItem( tmpPath, this );
148 if ( item )
149 {
150 // the item comes with zipped file name, set the name to relative path within zip file
151 item->setName( fileName );
152 children.append( item );
153 }
154 else
155 {
156 QgsDebugMsgLevel( u"not loaded item"_s, 3 );
157 }
158 }
159 }
160
161 return children;
162}
163
165{
166 return itemFromPath( parent, path, name, path );
167}
168
169QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &filePath, const QString &name, const QString &path )
170{
171 const QgsSettings settings;
172 const QString scanZipSetting = settings.value( u"qgis/scanZipInBrowser2"_s, "basic" ).toString();
173 QStringList zipFileList;
174 const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( filePath );
175 bool populated = false;
176
177 QgsDebugMsgLevel( u"path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4"_s.arg( path, name, scanZipSetting, vsiPrefix ), 3 );
178
179 // don't scan if scanZipBrowser == no
180 if ( scanZipSetting == "no"_L1 )
181 return nullptr;
182
183 // don't scan if this file is not a vsi container archive item
185 return nullptr;
186
187 auto zipItem = std::make_unique< QgsZipItem >( parent, name, filePath, path );
188 // force populate zipItem if it has less than 10 items and is not a .tgz or .tar.gz file (slow loading)
189 // for other items populating will be delayed until item is opened
190 // this might be polluting the tree with empty items but is necessary for performance reasons
191 // could also accept all files smaller than a certain size and add options for file count and/or size
192
193 // first get list of files inside .zip or .tar files
194 if ( path.endsWith( ".zip"_L1, Qt::CaseInsensitive ) ||
195 path.endsWith( ".tar"_L1, Qt::CaseInsensitive ) )
196 {
197 zipFileList = zipItem->getZipFileList();
198 }
199 // force populate if less than 10 items
200 if ( !zipFileList.isEmpty() && zipFileList.count() <= 10 )
201 {
202 zipItem->populate( zipItem->createChildren() );
203 populated = true; // there is no QgsDataItem::isPopulated() function
204 QgsDebugMsgLevel( u"Got zipItem with %1 children, path=%2, name=%3"_s.arg( zipItem->rowCount() ).arg( zipItem->path(), zipItem->name() ), 3 );
205 }
206 else
207 {
208 QgsDebugMsgLevel( u"Delaying populating zipItem with path=%1, name=%2"_s.arg( zipItem->path(), zipItem->name() ), 3 );
209 }
210
211 // only display if has children or if is not populated
212 if ( !populated || zipItem->rowCount() > 0 )
213 {
214 QgsDebugMsgLevel( u"returning zipItem"_s, 3 );
215 return zipItem.release();
216 }
217
218 return nullptr;
219}
220
222{
223 if ( ! mZipFileList.isEmpty() )
224 return mZipFileList;
225
226 QString tmpPath;
227 const QgsSettings settings;
228 const QString scanZipSetting = settings.value( u"qgis/scanZipInBrowser2"_s, "basic" ).toString();
229
230 QgsDebugMsgLevel( u"mFilePath = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4"_s.arg( mFilePath, name(), scanZipSetting, mVsiPrefix ), 3 );
231
232 // if scanZipBrowser == no: skip to the next file
233 if ( scanZipSetting == "no"_L1 )
234 {
235 return mZipFileList;
236 }
237
238 // get list of files inside zip file
239 QgsDebugMsgLevel( u"Open file %1 with gdal vsi"_s.arg( mVsiPrefix + mFilePath ), 3 );
240 char **papszSiblingFiles = VSIReadDirRecursive( QString( mVsiPrefix + mFilePath ).toUtf8().constData() );
241 if ( papszSiblingFiles )
242 {
243 for ( int i = 0; papszSiblingFiles[i]; i++ )
244 {
245 tmpPath = papszSiblingFiles[i];
246 QgsDebugMsgLevel( u"Read file %1"_s.arg( tmpPath ), 3 );
247 // skip directories (files ending with /)
248 if ( tmpPath.right( 1 ) != "/"_L1 )
249 mZipFileList << tmpPath;
250 }
251 CSLDestroy( papszSiblingFiles );
252 }
253 else
254 {
255 QgsDebugError( u"Error reading %1"_s.arg( mFilePath ) );
256 }
257
258 return mZipFileList;
259}
260
261
@ ItemRepresentsFile
Item's path() directly represents a file on disk.
Definition qgis.h:978
@ Collection
A collection of items.
Definition qgis.h:939
static QgsDataItemProviderRegistry * dataItemProviderRegistry()
Returns the application's data item provider registry, which keeps a list of data item providers that...
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
QgsDataCollectionItem(QgsDataItem *parent, const QString &name, const QString &path=QString(), const QString &providerKey=QString())
Constructor for QgsDataCollectionItem, with the specified parent item.
QList< QgsDataItemProvider * > providers() const
Returns the list of available providers.
Interface for providers that add custom data items to the browser tree.
Qgis::BrowserItemType mType
QVector< QgsDataItem * > children() const
QgsDataItem(Qgis::BrowserItemType type, QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey=QString())
Constructor for QgsDataItem, with the specified parent item.
QString mIconName
QString name() const
Returns the name of the item (the displayed text for the item).
QString path() const
virtual void setCapabilities(Qgis::BrowserItemCapabilities capabilities)
Sets the capabilities for the data item.
void setName(const QString &name)
Sets the name of the item (the displayed text for the item).
QgsDataItem * parent() const
Gets item parent.
QString providerKey() const
Returns the provider key that created this item (e.g.
virtual Qgis::BrowserItemCapabilities capabilities2() const
Returns the capabilities for the data item.
static QString vsiPrefixForPath(const QString &path)
Returns a the vsi prefix which corresponds to a file path, or an empty string if the path is not asso...
static bool isVsiArchivePrefix(const QString &prefix)
Returns true if prefix is a supported archive style container prefix (e.g.
QList< QgsMimeDataUtils::Uri > UriList
Stores settings for use within QGIS.
Definition qgssettings.h:68
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static QIcon iconZip()
static Q_DECL_DEPRECATED QString vsiPrefix(const QString &uri)
QgsZipItem(QgsDataItem *parent, const QString &name, const QString &path)
Constructor.
QStringList mZipFileList
Definition qgszipitem.h:40
QStringList getZipFileList()
bool hasDragEnabled() const override
Returns true if the item may be dragged.
QgsMimeDataUtils::UriList mimeUris() const override
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
QString mFilePath
Definition qgszipitem.h:38
static QgsDataItem * itemFromPath(QgsDataItem *parent, const QString &path, const QString &name)
Creates a new data item from the specified path.
QString mVsiPrefix
Definition qgszipitem.h:39
QVector< QgsDataItem * > createChildren() override
Create children.
static QStringList sProviderNames
Definition qgszipitem.h:65
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QString filePath
Path to file, if uri is associated with a file.
QString uri
Identifier of the data source recognized by its providerKey.
QString layerType
Type of URI.