QGIS API Documentation 3.41.0-Master (fda2aa46e9a)
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#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 std::unique_ptr< QgsZipItem > 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 Collection: logical collection of layers or subcollections, e.g.
QList< QgsDataItemProvider * > providers() const
Returns the list of available providers.
This is the interface for those who want to 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
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
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:39
#define QgsDebugError(str)
Definition qgslogger.h:38
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.