1 /***************************************************************************
2     testqgsfilewidget.cpp
3      --------------------------------------
4     Date                 : December 2014
5     Copyright            : (C) 2014 Nyall Dawson
6     Email                : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 
17 #include "qgstest.h"
18 
19 #include "qgsfilewidget.h"
20 #include "qgsmimedatautils.h"
21 #include "qgsdataitem.h"
22 #include "qgsbrowsermodel.h"
23 #include "qgslayeritem.h"
24 #include "qgsdirectoryitem.h"
25 #include <memory>
26 
27 class TestQgsFileWidget: public QObject
28 {
29     Q_OBJECT
30   private slots:
31     void initTestCase(); // will be called before the first testfunction is executed.
32     void cleanupTestCase(); // will be called after the last testfunction was executed.
33     void init(); // will be called before each testfunction is executed.
34     void cleanup(); // will be called after every testfunction.
35     void relativePath();
36     void toUrl();
37     void testDroppedFiles();
38     void testMultipleFiles();
39     void testSplitFilePaths();
40 };
41 
initTestCase()42 void TestQgsFileWidget::initTestCase()
43 {
44 }
45 
cleanupTestCase()46 void TestQgsFileWidget::cleanupTestCase()
47 {
48 }
49 
init()50 void TestQgsFileWidget::init()
51 {
52 }
53 
cleanup()54 void TestQgsFileWidget::cleanup()
55 {
56 }
57 
relativePath()58 void TestQgsFileWidget::relativePath()
59 {
60   QgsFileWidget *w = new QgsFileWidget();
61   w->setDefaultRoot( QStringLiteral( "/home/test" ) );
62   w->setRelativeStorage( QgsFileWidget::Absolute );
63   QCOMPARE( w->relativePath( "/home/test2/file1.ext", true ), QString( "/home/test2/file1.ext" ) );
64   QCOMPARE( w->relativePath( "/home/test2/file2.ext", false ), QString( "/home/test2/file2.ext" ) );
65   w->setRelativeStorage( QgsFileWidget::RelativeDefaultPath );
66   QCOMPARE( w->relativePath( "/home/test2/file3.ext", true ), QString( "../test2/file3.ext" ) );
67   QCOMPARE( w->relativePath( "../test2/file4.ext", true ), QString( "../test2/file4.ext" ) );
68   QCOMPARE( w->relativePath( "/home/test2/file5.ext", false ), QString( "/home/test2/file5.ext" ) );
69   QCOMPARE( w->relativePath( "../test2/file6.ext", false ), QString( "/home/test2/file6.ext" ) );
70 }
71 
toUrl()72 void TestQgsFileWidget::toUrl()
73 {
74   QgsFileWidget *w = new QgsFileWidget();
75   w->setDefaultRoot( QStringLiteral( "/home/test" ) );
76   w->setRelativeStorage( QgsFileWidget::Absolute );
77   w->setFullUrl( true );
78   QCOMPARE( w->toUrl( "/home/test2/file1.ext" ), QString( "<a href=\"file:///home/test2/file1.ext\">/home/test2/file1.ext</a>" ) );
79   w->setFullUrl( false );
80   QCOMPARE( w->toUrl( "/home/test2/file2.ext" ), QString( "<a href=\"file:///home/test2/file2.ext\">file2.ext</a>" ) );
81   w->setRelativeStorage( QgsFileWidget::RelativeDefaultPath );
82   w->setFullUrl( true );
83   QCOMPARE( w->toUrl( "/home/test2/file3.ext" ), QString( "<a href=\"file:///home/test2/file3.ext\">/home/test2/file3.ext</a>" ) );
84   QCOMPARE( w->toUrl( "../test2/file4.ext" ), QString( "<a href=\"file:///home/test2/file4.ext\">../test2/file4.ext</a>" ) );
85   w->setFullUrl( false );
86   QCOMPARE( w->toUrl( "/home/test2/file5.ext" ), QString( "<a href=\"file:///home/test2/file5.ext\">file5.ext</a>" ) );
87   QCOMPARE( w->toUrl( "../test2/file6.ext" ), QString( "<a href=\"file:///home/test2/file6.ext\">file6.ext</a>" ) );
88 }
89 
testDroppedFiles()90 void TestQgsFileWidget::testDroppedFiles()
91 {
92   QgsFileWidget *w = new QgsFileWidget();
93   w->setStorageMode( QgsFileWidget::GetFile );
94 
95   // should not accept dropped folders
96   std::unique_ptr< QMimeData > mime( new QMimeData() );
97   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR ) );
98   std::unique_ptr< QDropEvent > event( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
99 
100   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
101   QVERIFY( w->lineEdit()->text().isEmpty() );
102 
103   // but dropped files should be fine
104   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
105   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton,  Qt::NoModifier ) );
106   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
107   QCOMPARE( w->lineEdit()->text(), QString( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
108 
109   // also should support files dragged from browser
110   mime->setUrls( QList<QUrl>() );
111   QgsMimeDataUtils::Uri uri;
112   uri.uri = TEST_DATA_DIR + QStringLiteral( "/mesh/quad_and_triangle.2dm" );
113   QgsMimeDataUtils::UriList uriList;
114   uriList << uri;
115   mime.reset( QgsMimeDataUtils::encodeUriList( uriList ) );
116   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton,  Qt::NoModifier ) );
117   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
118   QCOMPARE( w->lineEdit()->text(), QString( TEST_DATA_DIR + QStringLiteral( "/mesh/quad_and_triangle.2dm" ) ) );
119 
120   QgsBrowserModel m;
121   m.initialize();
122   QgsLayerItem *layerItem = new QgsLayerItem( nullptr, QStringLiteral( "Test" ), QString(), TEST_DATA_DIR + QStringLiteral( "/mesh/quad_and_triangle.txt" ), Qgis::BrowserLayerType::Mesh, "mdal" );
123   m.driveItems().first()->addChild( layerItem );
124   mime.reset( m.mimeData( QModelIndexList() << m.findItem( layerItem ) ) );
125   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
126   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
127   QCOMPARE( w->lineEdit()->text(), QString( QString( TEST_DATA_DIR ) + QStringLiteral( "/mesh/quad_and_triangle.txt" ) ) );
128 
129   // plain text should also be permitted
130   mime = std::make_unique< QMimeData >();
131   mime->setText( TEST_DATA_DIR + QStringLiteral( "/mesh/quad_and_triangle.2dm" ) );
132   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton,  Qt::NoModifier ) );
133   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
134   QCOMPARE( w->lineEdit()->text(), QString( TEST_DATA_DIR + QStringLiteral( "/mesh/quad_and_triangle.2dm" ) ) );
135 
136   mime.reset( new QMimeData() );
137   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
138   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton,  Qt::NoModifier ) );
139   // with file filter
140   w->setFilter( QStringLiteral( "Data (*.shp)" ) );
141   w->setFilePath( QString() );
142   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
143   QCOMPARE( w->lineEdit()->text(), QString( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
144   w->setFilePath( QString() );
145   // should be rejected, not compatible with filter
146   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/encoded_html.html" ) ) );
147   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton,  Qt::NoModifier ) );
148   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
149   QVERIFY( w->lineEdit()->text().isEmpty() );
150   // new filter, should be allowed now
151   w->setFilter( QStringLiteral( "Data (*.shp);;HTML (*.HTML)" ) );
152   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
153   QCOMPARE( w->lineEdit()->text(), QString( TEST_DATA_DIR + QStringLiteral( "/encoded_html.html" ) ) );
154 
155   //try with wildcard filter
156   w->setFilter( QStringLiteral( "All files (*.*);;Data (*.shp);;HTML (*.HTML)" ) );
157   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.prj" ) ) );
158   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton,  Qt::NoModifier ) );
159   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
160   QCOMPARE( w->lineEdit()->text(), QString( TEST_DATA_DIR + QStringLiteral( "/bug5598.prj" ) ) );
161 
162   // try with folders
163   w->setStorageMode( QgsFileWidget::GetDirectory );
164   w->setFilePath( QString() );
165   // dropping a file should accept only the folder containing that file
166   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/mesh/quad_and_triangle.2dm" ) ) );
167   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton,  Qt::NoModifier ) );
168   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
169   QCOMPARE( w->lineEdit()->text(), QString( QString( TEST_DATA_DIR ) +  QStringLiteral( "/mesh" ) ) );
170 
171   // but dropping a folder should work
172   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR ) );
173   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
174   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
175   QCOMPARE( w->lineEdit()->text(), QString( TEST_DATA_DIR ) );
176 
177   // integration test - dropping a directory item's mime data
178   QgsDirectoryItem *dirItem = new QgsDirectoryItem( nullptr, QStringLiteral( "Test" ), TEST_DATA_DIR + QStringLiteral( "/mesh" ) );
179   m.driveItems().first()->addChild( dirItem );
180   mime.reset( m.mimeData( QModelIndexList() << m.findItem( dirItem ) ) );
181   event.reset( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
182   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
183   QCOMPARE( w->lineEdit()->text(), QString( QString( TEST_DATA_DIR ) + QStringLiteral( "/mesh" ) ) );
184 }
185 
testMultipleFiles()186 void TestQgsFileWidget::testMultipleFiles()
187 {
188   QgsFileWidget *w = new QgsFileWidget();
189   w->setStorageMode( QgsFileWidget::GetMultipleFiles );
190 
191   std::unique_ptr< QMimeData > mime( new QMimeData() );
192   mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) )
193                  << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/elev.gpx" ) ) );
194   const std::unique_ptr< QDropEvent > event( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
195 
196   qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
197   QCOMPARE( w->lineEdit()->text(), QStringLiteral( "\"%1\" \"%2\"" ).arg( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) )
198             .arg( TEST_DATA_DIR + QStringLiteral( "/elev.gpx" ) ) );
199 }
200 
201 
testSplitFilePaths()202 void TestQgsFileWidget::testSplitFilePaths()
203 {
204   const QString path = QString( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) );
205   QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%1\"" ).arg( path ) ), QStringList() << path << path );
206   QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\"   \"%1\"" ).arg( path ) ), QStringList() << path << path );
207   QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\"   \"%1\"" ).arg( path ) ), QStringList() << path << path );
208   QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\"   \"%1\" " ).arg( path ) ), QStringList() << path << path );
209   QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\"   \"%1\" " ).arg( path ) ), QStringList() << path << path );
210   QCOMPARE( QgsFileWidget::splitFilePaths( path ), QStringList() << path );
211 }
212 
213 QGSTEST_MAIN( TestQgsFileWidget )
214 #include "testqgsfilewidget.moc"
215