QGIS API Documentation 3.43.0-Master (c67cf405802)
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#include "moc_qgszipitem.cpp"
20#include "qgsapplication.h"
21#include "qgsdataitemprovider.h"
23#include "qgssettings.h"
24#include "qgsgdalutils.h"
25
26#include <QFileInfo>
27
28#include <cpl_vsi.h>
29#include <cpl_string.h>
30#include <mutex>
31
33{
34 return QgsApplication::getThemeIcon( QStringLiteral( "/mIconZip.svg" ) );
35}
36
37
38//-----------------------------------------------------------------------
39QStringList QgsZipItem::sProviderNames = QStringList();
40
41
42QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString &path )
43 : QgsDataCollectionItem( parent, name, path )
44{
46 init();
47}
48
49QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name,
50 const QString &filePath, const QString &path,
51 const QString &providerKey )
52 : QgsDataCollectionItem( parent, name, path, providerKey )
53 , mFilePath( filePath )
54{
55 init();
56}
57
58void QgsZipItem::init()
59{
61 mIconName = QStringLiteral( "/mIconZip.svg" );
63
65
66 static std::once_flag initialized;
67 std::call_once( initialized, [ = ]
68 {
69 sProviderNames << QStringLiteral( "files" );
70 } );
71}
72
74{
75 return true;
76}
77
79{
81 u.layerType = QStringLiteral( "collection" );
82 u.uri = path();
83 u.filePath = path();
84 return { u };
85}
86
87QString QgsZipItem::vsiPrefix( const QString &uri )
88{
90}
91
92QVector<QgsDataItem *> QgsZipItem::createChildren()
93{
94 QVector<QgsDataItem *> children;
95 QString tmpPath;
96 const QgsSettings settings;
97 const QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
98
99 mZipFileList.clear();
100
101 QgsDebugMsgLevel( QStringLiteral( "mFilePath = %1 path = %2 name= %3 scanZipSetting= %4 vsiPrefix= %5" ).arg( mFilePath, path(), name(), scanZipSetting, mVsiPrefix ), 3 );
102
103 // if scanZipBrowser == no: skip to the next file
104 if ( scanZipSetting == QLatin1String( "no" ) )
105 {
106 return children;
107 }
108
109 // first get list of files
111
112 const QList<QgsDataItemProvider *> providers = QgsApplication::dataItemProviderRegistry()->providers();
113
114 // loop over files inside zip
115 const auto constMZipFileList = mZipFileList;
116 for ( const QString &fileName : constMZipFileList )
117 {
118 const QFileInfo info( fileName );
119 tmpPath = mVsiPrefix + mFilePath + '/' + fileName;
120 QgsDebugMsgLevel( "tmpPath = " + tmpPath, 3 );
121
122 for ( QgsDataItemProvider *provider : providers )
123 {
124 if ( !sProviderNames.contains( provider->name() ) )
125 continue;
126
127 // ugly hack to remove .dbf file if there is a .shp file
128 if ( provider->name() == QLatin1String( "OGR" ) )
129 {
130 if ( info.suffix().compare( QLatin1String( "dbf" ), Qt::CaseInsensitive ) == 0 )
131 {
132 if ( mZipFileList.indexOf( fileName.left( fileName.count() - 4 ) + ".shp" ) != -1 )
133 continue;
134 }
135 if ( info.completeSuffix().compare( QLatin1String( "shp.xml" ), Qt::CaseInsensitive ) == 0 )
136 {
137 continue;
138 }
139 }
140
141 QgsDebugMsgLevel( QStringLiteral( "trying to load item %1 with %2" ).arg( tmpPath, provider->name() ), 3 );
142 QgsDataItem *item = provider->createDataItem( tmpPath, this );
143 if ( item )
144 {
145 // the item comes with zipped file name, set the name to relative path within zip file
146 item->setName( fileName );
147 children.append( item );
148 }
149 else
150 {
151 QgsDebugMsgLevel( QStringLiteral( "not loaded item" ), 3 );
152 }
153 }
154 }
155
156 return children;
157}
158
159QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &path, const QString &name )
160{
161 return itemFromPath( parent, path, name, path );
162}
163
164QgsDataItem *QgsZipItem::itemFromPath( QgsDataItem *parent, const QString &filePath, const QString &name, const QString &path )
165{
166 const QgsSettings settings;
167 const QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
168 QStringList zipFileList;
169 const QString vsiPrefix = QgsGdalUtils::vsiPrefixForPath( filePath );
170 bool populated = false;
171
172 QgsDebugMsgLevel( QStringLiteral( "path = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( path, name, scanZipSetting, vsiPrefix ), 3 );
173
174 // don't scan if scanZipBrowser == no
175 if ( scanZipSetting == QLatin1String( "no" ) )
176 return nullptr;
177
178 // don't scan if this file is not a vsi container archive item
180 return nullptr;
181
182 auto zipItem = std::make_unique< QgsZipItem >( parent, name, filePath, path );
183 // force populate zipItem if it has less than 10 items and is not a .tgz or .tar.gz file (slow loading)
184 // for other items populating will be delayed until item is opened
185 // this might be polluting the tree with empty items but is necessary for performance reasons
186 // could also accept all files smaller than a certain size and add options for file count and/or size
187
188 // first get list of files inside .zip or .tar files
189 if ( path.endsWith( QLatin1String( ".zip" ), Qt::CaseInsensitive ) ||
190 path.endsWith( QLatin1String( ".tar" ), Qt::CaseInsensitive ) )
191 {
192 zipFileList = zipItem->getZipFileList();
193 }
194 // force populate if less than 10 items
195 if ( !zipFileList.isEmpty() && zipFileList.count() <= 10 )
196 {
197 zipItem->populate( zipItem->createChildren() );
198 populated = true; // there is no QgsDataItem::isPopulated() function
199 QgsDebugMsgLevel( QStringLiteral( "Got zipItem with %1 children, path=%2, name=%3" ).arg( zipItem->rowCount() ).arg( zipItem->path(), zipItem->name() ), 3 );
200 }
201 else
202 {
203 QgsDebugMsgLevel( QStringLiteral( "Delaying populating zipItem with path=%1, name=%2" ).arg( zipItem->path(), zipItem->name() ), 3 );
204 }
205
206 // only display if has children or if is not populated
207 if ( !populated || zipItem->rowCount() > 0 )
208 {
209 QgsDebugMsgLevel( QStringLiteral( "returning zipItem" ), 3 );
210 return zipItem.release();
211 }
212
213 return nullptr;
214}
215
217{
218 if ( ! mZipFileList.isEmpty() )
219 return mZipFileList;
220
221 QString tmpPath;
222 const QgsSettings settings;
223 const QString scanZipSetting = settings.value( QStringLiteral( "qgis/scanZipInBrowser2" ), "basic" ).toString();
224
225 QgsDebugMsgLevel( QStringLiteral( "mFilePath = %1 name= %2 scanZipSetting= %3 vsiPrefix= %4" ).arg( mFilePath, name(), scanZipSetting, mVsiPrefix ), 3 );
226
227 // if scanZipBrowser == no: skip to the next file
228 if ( scanZipSetting == QLatin1String( "no" ) )
229 {
230 return mZipFileList;
231 }
232
233 // get list of files inside zip file
234 QgsDebugMsgLevel( QStringLiteral( "Open file %1 with gdal vsi" ).arg( mVsiPrefix + mFilePath ), 3 );
235 char **papszSiblingFiles = VSIReadDirRecursive( QString( mVsiPrefix + mFilePath ).toUtf8().constData() );
236 if ( papszSiblingFiles )
237 {
238 for ( int i = 0; papszSiblingFiles[i]; i++ )
239 {
240 tmpPath = papszSiblingFiles[i];
241 QgsDebugMsgLevel( QStringLiteral( "Read file %1" ).arg( tmpPath ), 3 );
242 // skip directories (files ending with /)
243 if ( tmpPath.right( 1 ) != QLatin1String( "/" ) )
244 mZipFileList << tmpPath;
245 }
246 CSLDestroy( papszSiblingFiles );
247 }
248 else
249 {
250 QgsDebugError( QStringLiteral( "Error reading %1" ).arg( mFilePath ) );
251 }
252
253 return mZipFileList;
254}
255
256
@ ItemRepresentsFile
Item's path() directly represents a file on disk.
@ Collection
A collection of items.
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.
A browser item for collections of data.
QList< QgsDataItemProvider * > providers() const
Returns the list of available providers.
Interface for providers that add custom data items to the browser tree.
Base class for all items in the model.
Definition qgsdataitem.h:46
Qgis::BrowserItemType mType
QVector< QgsDataItem * > children() const
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.
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:66
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:36
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:34
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:35
QVector< QgsDataItem * > createChildren() override
Create children.
static QStringList sProviderNames
Definition qgszipitem.h:61
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:41
#define QgsDebugError(str)
Definition qgslogger.h:40
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.