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