/src/libreoffice/svtools/source/control/inettbc.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #ifdef UNX |
21 | | #include <pwd.h> |
22 | | #endif |
23 | | |
24 | | #include <svtools/inettbc.hxx> |
25 | | #include <comphelper/diagnose_ex.hxx> |
26 | | #include <com/sun/star/uno/Any.hxx> |
27 | | #include <com/sun/star/uno/Reference.hxx> |
28 | | #include <com/sun/star/beans/Property.hpp> |
29 | | #include <com/sun/star/sdbc/XResultSet.hpp> |
30 | | #include <com/sun/star/sdbc/XRow.hpp> |
31 | | #include <com/sun/star/task/XInteractionHandler.hpp> |
32 | | #include <com/sun/star/ucb/NumberedSortingInfo.hpp> |
33 | | #include <com/sun/star/ucb/UniversalContentBroker.hpp> |
34 | | #include <com/sun/star/ucb/XAnyCompareFactory.hpp> |
35 | | #include <com/sun/star/ucb/XCommandProcessor2.hpp> |
36 | | #include <com/sun/star/ucb/XProgressHandler.hpp> |
37 | | #include <com/sun/star/ucb/XContentAccess.hpp> |
38 | | #include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp> |
39 | | #include <comphelper/processfactory.hxx> |
40 | | #include <comphelper/string.hxx> |
41 | | #include <salhelper/thread.hxx> |
42 | | #include <tools/debug.hxx> |
43 | | #include <o3tl/string_view.hxx> |
44 | | #include <osl/file.hxx> |
45 | | #include <osl/mutex.hxx> |
46 | | #include <osl/process.h> |
47 | | #include <unotools/historyoptions.hxx> |
48 | | #include <unotools/pathoptions.hxx> |
49 | | #include <ucbhelper/commandenvironment.hxx> |
50 | | #include <ucbhelper/content.hxx> |
51 | | #include <unotools/ucbhelper.hxx> |
52 | | #include <svtools/asynclink.hxx> |
53 | | #include <svtools/urlfilter.hxx> |
54 | | |
55 | | #include <mutex> |
56 | | #include <utility> |
57 | | #include <vector> |
58 | | #include <algorithm> |
59 | | |
60 | | using namespace ::ucbhelper; |
61 | | using namespace ::utl; |
62 | | using namespace ::com::sun::star; |
63 | | using namespace ::com::sun::star::beans; |
64 | | using namespace ::com::sun::star::sdbc; |
65 | | using namespace ::com::sun::star::task; |
66 | | using namespace ::com::sun::star::ucb; |
67 | | using namespace ::com::sun::star::uno; |
68 | | |
69 | | class SvtURLBox_Impl |
70 | | { |
71 | | public: |
72 | | std::vector<OUString> aURLs; |
73 | | std::vector<OUString> aCompletions; |
74 | | std::vector<WildCard> m_aFilters; |
75 | | |
76 | | static bool TildeParsing( OUString& aText, OUString& aBaseUrl ); |
77 | | |
78 | | SvtURLBox_Impl( ) |
79 | 0 | { |
80 | 0 | FilterMatch::createWildCardFilterList(u"",m_aFilters); |
81 | 0 | } |
82 | | }; |
83 | | |
84 | | class SvtMatchContext_Impl: public salhelper::Thread |
85 | | { |
86 | | std::vector<OUString> aPickList; |
87 | | std::vector<OUString> aCompletions; |
88 | | std::vector<OUString> aURLs; |
89 | | svtools::AsynchronLink aLink; |
90 | | OUString aText; |
91 | | SvtURLBox* pBox; |
92 | | bool bOnlyDirectories; |
93 | | bool bNoSelection; |
94 | | |
95 | | std::mutex mutex_; |
96 | | bool stopped_; |
97 | | css::uno::Reference< css::ucb::XCommandProcessor > processor_; |
98 | | sal_Int32 commandId_; |
99 | | |
100 | | DECL_LINK( Select_Impl, void*, void ); |
101 | | |
102 | | virtual ~SvtMatchContext_Impl() override; |
103 | | virtual void execute() override; |
104 | | void doExecute(); |
105 | | void Insert( const OUString& rCompletion, const OUString& rURL, bool bForce = false); |
106 | | void ReadFolder( const OUString& rURL, const OUString& rMatch, bool bSmart ); |
107 | | static void FillPicklist(std::vector<OUString>& rPickList); |
108 | | |
109 | | public: |
110 | | SvtMatchContext_Impl( SvtURLBox* pBoxP, OUString aText ); |
111 | | void Stop(); |
112 | | }; |
113 | | |
114 | | |
115 | | namespace |
116 | | { |
117 | | ::osl::Mutex& theSvtMatchContextMutex() |
118 | 0 | { |
119 | 0 | static ::osl::Mutex SINGLETON; |
120 | 0 | return SINGLETON; |
121 | 0 | } |
122 | | } |
123 | | |
124 | | SvtMatchContext_Impl::SvtMatchContext_Impl(SvtURLBox* pBoxP, OUString _aText) |
125 | 0 | : Thread( "MatchContext_Impl" ) |
126 | 0 | , aLink( LINK( this, SvtMatchContext_Impl, Select_Impl ) ) |
127 | 0 | , aText(std::move( _aText )) |
128 | 0 | , pBox( pBoxP ) |
129 | 0 | , bOnlyDirectories( pBoxP->bOnlyDirectories ) |
130 | 0 | , bNoSelection( pBoxP->bNoSelection ) |
131 | 0 | , stopped_(false) |
132 | 0 | , commandId_(0) |
133 | 0 | { |
134 | 0 | FillPicklist( aPickList ); |
135 | 0 | } |
136 | | |
137 | | SvtMatchContext_Impl::~SvtMatchContext_Impl() |
138 | 0 | { |
139 | 0 | aLink.ClearPendingCall(); |
140 | 0 | } |
141 | | |
142 | | void SvtMatchContext_Impl::FillPicklist(std::vector<OUString>& rPickList) |
143 | 0 | { |
144 | | // Read the history of picks |
145 | 0 | std::vector< SvtHistoryOptions::HistoryItem > seqPicklist = SvtHistoryOptions::GetList( EHistoryType::PickList ); |
146 | 0 | sal_uInt32 nCount = seqPicklist.size(); |
147 | |
|
148 | 0 | for( sal_uInt32 nItem=0; nItem < nCount; nItem++ ) |
149 | 0 | { |
150 | 0 | INetURLObject aURL; |
151 | 0 | aURL.SetURL( seqPicklist[nItem].sTitle ); |
152 | 0 | rPickList.insert(rPickList.begin() + nItem, aURL.GetMainURL(INetURLObject::DecodeMechanism::WithCharset)); |
153 | 0 | } |
154 | 0 | } |
155 | | |
156 | | void SvtMatchContext_Impl::Stop() |
157 | 0 | { |
158 | 0 | css::uno::Reference< css::ucb::XCommandProcessor > proc; |
159 | 0 | sal_Int32 id(0); |
160 | 0 | { |
161 | 0 | std::scoped_lock g(mutex_); |
162 | 0 | if (!stopped_) { |
163 | 0 | stopped_ = true; |
164 | 0 | proc = processor_; |
165 | 0 | id = commandId_; |
166 | 0 | } |
167 | 0 | } |
168 | 0 | if (proc.is()) { |
169 | 0 | proc->abort(id); |
170 | 0 | } |
171 | 0 | terminate(); |
172 | 0 | } |
173 | | |
174 | | void SvtMatchContext_Impl::execute( ) |
175 | 0 | { |
176 | 0 | doExecute(); |
177 | 0 | aLink.Call( this ); |
178 | 0 | } |
179 | | |
180 | | |
181 | | // This method is called via AsynchronLink, so it has the SolarMutex and |
182 | | // calling solar code ( VCL ... ) is safe. It is called when the thread is |
183 | | // terminated ( finished work or stopped ). Cancelling the thread via |
184 | | // Cancellable does not discard the information gained so far, it |
185 | | // inserts all collected completions into the listbox. |
186 | | |
187 | | IMPL_LINK_NOARG( SvtMatchContext_Impl, Select_Impl, void*, void ) |
188 | 0 | { |
189 | | // avoid recursion through cancel button |
190 | 0 | { |
191 | 0 | std::scoped_lock g(mutex_); |
192 | 0 | if (stopped_) { |
193 | | // Completion was stopped, no display: |
194 | 0 | return; |
195 | 0 | } |
196 | 0 | } |
197 | | |
198 | | // insert all completed strings into the listbox |
199 | 0 | pBox->clear(); |
200 | |
|
201 | 0 | for (auto const& completion : aCompletions) |
202 | 0 | { |
203 | | // convert the file into a URL |
204 | 0 | OUString sURL; |
205 | 0 | osl::FileBase::getFileURLFromSystemPath(completion, sURL); |
206 | | // note: if this doesn't work, we're not interested in: we're checking the |
207 | | // untouched sCompletion then |
208 | |
|
209 | 0 | if ( !sURL.isEmpty() && !sURL.endsWith("/") ) |
210 | 0 | { |
211 | 0 | OUString sUpperURL( sURL.toAsciiUpperCase() ); |
212 | |
|
213 | 0 | if ( ::std::none_of( pBox->pImpl->m_aFilters.begin(), |
214 | 0 | pBox->pImpl->m_aFilters.end(), |
215 | 0 | FilterMatch( sUpperURL ) ) ) |
216 | 0 | { // this URL is not allowed |
217 | 0 | continue; |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | 0 | pBox->append_text(completion); |
222 | 0 | } |
223 | |
|
224 | 0 | pBox->EnableAutocomplete(!bNoSelection); |
225 | | |
226 | | // transfer string lists to listbox and forget them |
227 | 0 | pBox->pImpl->aURLs = aURLs; |
228 | 0 | pBox->pImpl->aCompletions = aCompletions; |
229 | 0 | aURLs.clear(); |
230 | 0 | aCompletions.clear(); |
231 | | |
232 | | // the box has this control as a member so we have to set that member |
233 | | // to zero before deleting ourself. |
234 | 0 | pBox->pCtx.clear(); |
235 | 0 | } |
236 | | |
237 | | void SvtMatchContext_Impl::Insert( const OUString& rCompletion, |
238 | | const OUString& rURL, |
239 | | bool bForce ) |
240 | 0 | { |
241 | 0 | if( !bForce ) |
242 | 0 | { |
243 | | // avoid doubles |
244 | 0 | if(find(aCompletions.begin(), aCompletions.end(), rCompletion) != aCompletions.end()) |
245 | 0 | return; |
246 | 0 | } |
247 | | |
248 | 0 | aCompletions.push_back(rCompletion); |
249 | 0 | aURLs.push_back(rURL); |
250 | 0 | } |
251 | | |
252 | | |
253 | | void SvtMatchContext_Impl::ReadFolder( const OUString& rURL, |
254 | | const OUString& rMatch, |
255 | | bool bSmart ) |
256 | 0 | { |
257 | | // check folder to scan |
258 | 0 | if( !UCBContentHelper::IsFolder( rURL ) ) |
259 | 0 | return; |
260 | | |
261 | 0 | bool bPureHomePath = false; |
262 | 0 | #ifdef UNX |
263 | 0 | bPureHomePath = aText.startsWith( "~" ) && aText.indexOf( '/' ) == -1; |
264 | 0 | #endif |
265 | |
|
266 | 0 | bool bExectMatch = bPureHomePath |
267 | 0 | || aText == "." |
268 | 0 | || aText.endsWith("/.") |
269 | 0 | || aText.endsWith("/.."); |
270 | | |
271 | | // for pure home paths ( ~username ) the '.' at the end of rMatch |
272 | | // means that it points to root catalog |
273 | | // this is done only for file contents since home paths parsing is useful only for them |
274 | 0 | if ( bPureHomePath && rMatch == "file:///." ) |
275 | 0 | { |
276 | | // a home that refers to / |
277 | |
|
278 | 0 | OUString aNewText = aText + "/"; |
279 | 0 | Insert( aNewText, rURL, true ); |
280 | |
|
281 | 0 | return; |
282 | 0 | } |
283 | | |
284 | | // string to match with |
285 | 0 | INetURLObject aMatchObj( rMatch ); |
286 | 0 | OUString aMatchName; |
287 | |
|
288 | 0 | if ( rURL != aMatchObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) |
289 | 0 | { |
290 | 0 | aMatchName = aMatchObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ); |
291 | | |
292 | | // matching is always done case insensitive, but completion will be case sensitive and case preserving |
293 | 0 | aMatchName = aMatchName.toAsciiLowerCase(); |
294 | | |
295 | | // if the matchstring ends with a slash, we must search for this also |
296 | 0 | if ( rMatch.endsWith("/") ) |
297 | 0 | aMatchName += "/"; |
298 | 0 | } |
299 | |
|
300 | 0 | sal_Int32 nMatchLen = aMatchName.getLength(); |
301 | |
|
302 | 0 | INetURLObject aFolderObj( rURL ); |
303 | 0 | DBG_ASSERT( aFolderObj.GetProtocol() != INetProtocol::NotValid, "Invalid URL!" ); |
304 | |
|
305 | 0 | try |
306 | 0 | { |
307 | 0 | Content aCnt( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), |
308 | 0 | new ::ucbhelper::CommandEnvironment( uno::Reference< XInteractionHandler >(), |
309 | 0 | uno::Reference< XProgressHandler >() ), |
310 | 0 | comphelper::getProcessComponentContext() ); |
311 | 0 | uno::Reference< XResultSet > xResultSet; |
312 | |
|
313 | 0 | try |
314 | 0 | { |
315 | 0 | ResultSetInclude eInclude = INCLUDE_FOLDERS_AND_DOCUMENTS; |
316 | 0 | if ( bOnlyDirectories ) |
317 | 0 | eInclude = INCLUDE_FOLDERS_ONLY; |
318 | 0 | uno::Reference< XDynamicResultSet > xDynResultSet = aCnt.createDynamicCursor( { u"Title"_ustr, u"IsFolder"_ustr }, eInclude ); |
319 | |
|
320 | 0 | uno::Reference < XAnyCompareFactory > xCompare; |
321 | 0 | uno::Reference < XSortedDynamicResultSetFactory > xSRSFac = |
322 | 0 | SortedDynamicResultSetFactory::create( ::comphelper::getProcessComponentContext() ); |
323 | |
|
324 | 0 | uno::Reference< XDynamicResultSet > xDynamicResultSet = |
325 | 0 | xSRSFac->createSortedDynamicResultSet( xDynResultSet, { { 2, false }, { 1, true } }, xCompare ); |
326 | |
|
327 | 0 | if ( xDynamicResultSet.is() ) |
328 | 0 | { |
329 | 0 | xResultSet = xDynamicResultSet->getStaticResultSet(); |
330 | 0 | } |
331 | 0 | } |
332 | 0 | catch( css::uno::Exception& ) {} |
333 | |
|
334 | 0 | if ( xResultSet.is() ) |
335 | 0 | { |
336 | 0 | uno::Reference< XRow > xRow( xResultSet, UNO_QUERY ); |
337 | 0 | uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); |
338 | |
|
339 | 0 | try |
340 | 0 | { |
341 | 0 | while ( schedule() && xResultSet->next() ) |
342 | 0 | { |
343 | 0 | OUString aURL = xContentAccess->queryContentIdentifierString(); |
344 | 0 | OUString aTitle = xRow->getString(1); |
345 | 0 | bool bIsFolder = xRow->getBoolean(2); |
346 | | |
347 | | // matching is always done case insensitive, but completion will be case sensitive and case preserving |
348 | 0 | aTitle = aTitle.toAsciiLowerCase(); |
349 | |
|
350 | 0 | if ( |
351 | 0 | !nMatchLen || |
352 | 0 | (bExectMatch && aMatchName == aTitle) || |
353 | 0 | (!bExectMatch && aTitle.startsWith(aMatchName)) |
354 | 0 | ) |
355 | 0 | { |
356 | | // all names fit if matchstring is empty |
357 | 0 | INetURLObject aObj( aURL ); |
358 | 0 | sal_Unicode aDelimiter = '/'; |
359 | 0 | if ( bSmart ) |
360 | | // when parsing is done "smart", the delimiter must be "guessed" |
361 | 0 | aObj.getFSysPath( static_cast<FSysStyle>(FSysStyle::Detect & ~FSysStyle::Vos), &aDelimiter ); |
362 | |
|
363 | 0 | if ( bIsFolder ) |
364 | 0 | aObj.setFinalSlash(); |
365 | | |
366 | | // get the last name of the URL |
367 | 0 | OUString aMatch = aObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ); |
368 | 0 | OUString aInput( aText ); |
369 | 0 | if ( nMatchLen ) |
370 | 0 | { |
371 | 0 | if (aText.endsWith(".") || bPureHomePath) |
372 | 0 | { |
373 | | // if a "special folder" URL was typed, don't touch the user input |
374 | 0 | aMatch = aMatch.copy( nMatchLen ); |
375 | 0 | } |
376 | 0 | else |
377 | 0 | { |
378 | | // make the user input case preserving |
379 | 0 | DBG_ASSERT( aInput.getLength() >= nMatchLen, "Suspicious Matching!" ); |
380 | 0 | aInput = aInput.copy( 0, aInput.getLength() - nMatchLen ); |
381 | 0 | } |
382 | 0 | } |
383 | |
|
384 | 0 | aInput += aMatch; |
385 | | |
386 | | // folders should get a final slash automatically |
387 | 0 | if ( bIsFolder ) |
388 | 0 | aInput += OUStringChar(aDelimiter); |
389 | |
|
390 | 0 | Insert( aInput, aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), true ); |
391 | 0 | } |
392 | 0 | } |
393 | 0 | } |
394 | 0 | catch( css::uno::Exception& ) |
395 | 0 | { |
396 | 0 | } |
397 | 0 | } |
398 | 0 | } |
399 | 0 | catch( css::uno::Exception& ) |
400 | 0 | { |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | | void SvtMatchContext_Impl::doExecute() |
405 | 0 | { |
406 | 0 | ::osl::MutexGuard aGuard( theSvtMatchContextMutex() ); |
407 | 0 | { |
408 | | // have we been stopped while we were waiting for the mutex? |
409 | 0 | std::scoped_lock g(mutex_); |
410 | 0 | if (stopped_) { |
411 | 0 | return; |
412 | 0 | } |
413 | 0 | } |
414 | | |
415 | | // Reset match lists |
416 | 0 | aCompletions.clear(); |
417 | 0 | aURLs.clear(); |
418 | | |
419 | | // check for input |
420 | 0 | if ( aText.isEmpty() ) |
421 | 0 | return; |
422 | | |
423 | 0 | if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 ) |
424 | | // no autocompletion for wildcards |
425 | 0 | return; |
426 | | |
427 | 0 | OUString aMatch; |
428 | 0 | INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText ); |
429 | 0 | INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( pBox->aBaseURL ); |
430 | 0 | if ( pBox->aBaseURL.isEmpty() ) |
431 | 0 | eBaseProt = INetURLObject::CompareProtocolScheme( SvtPathOptions().GetWorkPath() ); |
432 | 0 | INetProtocol eSmartProt = pBox->GetSmartProtocol(); |
433 | | |
434 | | // if the user input is a valid URL, go on with it |
435 | | // otherwise it could be parsed smart with a predefined smart protocol |
436 | | // ( or if this is not set with the protocol of a predefined base URL ) |
437 | 0 | if( eProt == INetProtocol::NotValid || eProt == eSmartProt || (eSmartProt == INetProtocol::NotValid && eProt == eBaseProt) ) |
438 | 0 | { |
439 | | // not stopped yet ? |
440 | 0 | if( schedule() ) |
441 | 0 | { |
442 | 0 | if ( eProt == INetProtocol::NotValid ) |
443 | 0 | aMatch = SvtURLBox::ParseSmart( aText, pBox->aBaseURL ); |
444 | 0 | else |
445 | 0 | aMatch = aText; |
446 | 0 | if ( !aMatch.isEmpty() ) |
447 | 0 | { |
448 | 0 | INetURLObject aURLObject( aMatch ); |
449 | 0 | OUString aMainURL( aURLObject.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); |
450 | | // Disable autocompletion for anything but the (local) file |
451 | | // system (for which access is hopefully fast), as the logic of |
452 | | // how SvtMatchContext_Impl is used requires this code to run to |
453 | | // completion before further user input is processed, and even |
454 | | // SvtMatchContext_Impl::Stop does not guarantee a speedy |
455 | | // return: |
456 | 0 | if ( !aMainURL.isEmpty() |
457 | 0 | && aURLObject.GetProtocol() == INetProtocol::File ) |
458 | 0 | { |
459 | | // if text input is a directory, it must be part of the match list! Until then it is scanned |
460 | 0 | bool folder = false; |
461 | 0 | if (aURLObject.hasFinalSlash()) { |
462 | 0 | try { |
463 | 0 | const css::uno::Reference< css::uno::XComponentContext >& |
464 | 0 | ctx(comphelper::getProcessComponentContext()); |
465 | 0 | css::uno::Reference< |
466 | 0 | css::ucb::XUniversalContentBroker > ucb( |
467 | 0 | css::ucb::UniversalContentBroker::create( |
468 | 0 | ctx)); |
469 | 0 | css::uno::Sequence< css::beans::Property > prop{ |
470 | 0 | { /* Name */ u"IsFolder"_ustr, |
471 | 0 | /* Handle */ -1, |
472 | 0 | /* Type */ cppu::UnoType< bool >::get(), |
473 | 0 | /* Attributes */ {} } |
474 | 0 | }; |
475 | 0 | css::uno::Any res; |
476 | 0 | css::uno::Reference< css::ucb::XCommandProcessor > |
477 | 0 | proc( |
478 | 0 | ucb->queryContent( |
479 | 0 | ucb->createContentIdentifier(aMainURL)), |
480 | 0 | css::uno::UNO_QUERY_THROW); |
481 | 0 | css::uno::Reference< css::ucb::XCommandProcessor2 > |
482 | 0 | proc2(proc, css::uno::UNO_QUERY); |
483 | 0 | sal_Int32 id = proc->createCommandIdentifier(); |
484 | 0 | try { |
485 | 0 | { |
486 | 0 | std::scoped_lock g(mutex_); |
487 | 0 | processor_ = proc; |
488 | 0 | commandId_ = id; |
489 | 0 | } |
490 | 0 | res = proc->execute( |
491 | 0 | css::ucb::Command( |
492 | 0 | u"getPropertyValues"_ustr, -1, |
493 | 0 | css::uno::Any(prop)), |
494 | 0 | id, |
495 | 0 | css::uno::Reference< |
496 | 0 | css::ucb::XCommandEnvironment >()); |
497 | 0 | } catch (...) { |
498 | 0 | if (proc2.is()) { |
499 | 0 | try { |
500 | 0 | proc2->releaseCommandIdentifier(id); |
501 | 0 | } catch (css::uno::RuntimeException &) { |
502 | 0 | TOOLS_WARN_EXCEPTION("svtools.control", "ignoring"); |
503 | 0 | } |
504 | 0 | } |
505 | 0 | throw; |
506 | 0 | } |
507 | 0 | if (proc2.is()) { |
508 | 0 | proc2->releaseCommandIdentifier(id); |
509 | 0 | } |
510 | 0 | { |
511 | 0 | std::scoped_lock g(mutex_); |
512 | 0 | processor_.clear(); |
513 | | // At least the neon-based WebDAV UCP does not |
514 | | // properly support aborting commands, so return |
515 | | // anyway now if an abort request had been |
516 | | // ignored and the command execution only |
517 | | // returned "successfully" after some timeout: |
518 | 0 | if (stopped_) { |
519 | 0 | return; |
520 | 0 | } |
521 | 0 | } |
522 | 0 | css::uno::Reference< css::sdbc::XRow > row( |
523 | 0 | res, css::uno::UNO_QUERY_THROW); |
524 | 0 | folder = row->getBoolean(1) && !row->wasNull(); |
525 | 0 | } catch (css::uno::Exception &) { |
526 | 0 | TOOLS_WARN_EXCEPTION("svtools.control", "ignoring"); |
527 | 0 | return; |
528 | 0 | } |
529 | 0 | } |
530 | 0 | if (folder) |
531 | 0 | Insert( aText, aMatch ); |
532 | 0 | else |
533 | | // otherwise the parent folder will be taken |
534 | 0 | aURLObject.removeSegment(); |
535 | | |
536 | | // scan directory and insert all matches |
537 | 0 | ReadFolder( aURLObject.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aMatch, eProt == INetProtocol::NotValid ); |
538 | 0 | } |
539 | 0 | } |
540 | 0 | } |
541 | 0 | } |
542 | | |
543 | 0 | if ( bOnlyDirectories ) |
544 | | // don't scan history picklist if only directories are allowed, picklist contains only files |
545 | 0 | return; |
546 | | |
547 | 0 | bool bFull = false; |
548 | |
|
549 | 0 | INetURLObject aCurObj; |
550 | 0 | OUString aCurString, aCurMainURL; |
551 | 0 | INetURLObject aObj; |
552 | 0 | aObj.SetSmartProtocol( eSmartProt == INetProtocol::NotValid ? INetProtocol::Http : eSmartProt ); |
553 | 0 | for( ;; ) |
554 | 0 | { |
555 | 0 | for(const auto& rPick : aPickList) |
556 | 0 | { |
557 | 0 | if (!schedule()) |
558 | 0 | break; |
559 | | |
560 | 0 | aCurObj.SetURL(rPick); |
561 | 0 | aCurObj.SetSmartURL( aCurObj.GetURLNoPass()); |
562 | 0 | aCurMainURL = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
563 | |
|
564 | 0 | if( eProt != INetProtocol::NotValid && aCurObj.GetProtocol() != eProt ) |
565 | 0 | continue; |
566 | | |
567 | 0 | if( eSmartProt != INetProtocol::NotValid && aCurObj.GetProtocol() != eSmartProt ) |
568 | 0 | continue; |
569 | | |
570 | 0 | switch( aCurObj.GetProtocol() ) |
571 | 0 | { |
572 | 0 | case INetProtocol::Http: |
573 | 0 | case INetProtocol::Https: |
574 | 0 | case INetProtocol::Ftp: |
575 | 0 | { |
576 | 0 | if( eProt == INetProtocol::NotValid && !bFull ) |
577 | 0 | { |
578 | 0 | aObj.SetSmartURL( aText ); |
579 | 0 | if( aObj.GetURLPath().getLength() > 1 ) |
580 | 0 | continue; |
581 | 0 | } |
582 | | |
583 | 0 | aCurString = aCurMainURL; |
584 | 0 | if( eProt == INetProtocol::NotValid ) |
585 | 0 | { |
586 | | // try if text matches the scheme |
587 | 0 | OUString aScheme( INetURLObject::GetScheme( aCurObj.GetProtocol() ) ); |
588 | 0 | if ( aScheme.startsWithIgnoreAsciiCase( aText ) && aText.getLength() < aScheme.getLength() ) |
589 | 0 | { |
590 | 0 | if( bFull ) |
591 | 0 | aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
592 | 0 | else |
593 | 0 | { |
594 | 0 | aCurObj.SetMark( u"" ); |
595 | 0 | aCurObj.SetParam( u"" ); |
596 | 0 | aCurObj.SetURLPath( u"" ); |
597 | 0 | aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
598 | 0 | } |
599 | |
|
600 | 0 | Insert( aMatch, aMatch ); |
601 | 0 | } |
602 | | |
603 | | // now try smart matching |
604 | 0 | aCurString = aCurString.copy( aScheme.getLength() ); |
605 | 0 | } |
606 | |
|
607 | 0 | if( aCurString.startsWithIgnoreAsciiCase( aText ) ) |
608 | 0 | { |
609 | 0 | if( bFull ) |
610 | 0 | aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
611 | 0 | else |
612 | 0 | { |
613 | 0 | aCurObj.SetMark( u"" ); |
614 | 0 | aCurObj.SetParam( u"" ); |
615 | 0 | aCurObj.SetURLPath( u"" ); |
616 | 0 | aMatch = aCurObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
617 | 0 | } |
618 | |
|
619 | 0 | OUString aURL( aMatch ); |
620 | 0 | if( eProt == INetProtocol::NotValid ) |
621 | 0 | aMatch = aMatch.copy( INetURLObject::GetScheme( aCurObj.GetProtocol() ).getLength() ); |
622 | |
|
623 | 0 | if( aText.getLength() < aMatch.getLength() ) |
624 | 0 | Insert( aMatch, aURL ); |
625 | |
|
626 | 0 | continue; |
627 | 0 | } |
628 | 0 | break; |
629 | 0 | } |
630 | 0 | default: |
631 | 0 | { |
632 | 0 | if( bFull ) |
633 | 0 | continue; |
634 | | |
635 | 0 | if( aCurMainURL.startsWith(aText) ) |
636 | 0 | { |
637 | 0 | if( aText.getLength() < aCurMainURL.getLength() ) |
638 | 0 | Insert( aCurMainURL, aCurMainURL ); |
639 | |
|
640 | 0 | continue; |
641 | 0 | } |
642 | 0 | break; |
643 | 0 | } |
644 | 0 | } |
645 | 0 | } |
646 | | |
647 | 0 | if( !bFull ) |
648 | 0 | bFull = true; |
649 | 0 | else |
650 | 0 | break; |
651 | 0 | } |
652 | 0 | } |
653 | | |
654 | | /** Parse leading ~ for Unix systems, |
655 | | does nothing for Windows |
656 | | */ |
657 | | bool SvtURLBox_Impl::TildeParsing([[maybe_unused]] OUString& aText, |
658 | | [[maybe_unused]] OUString& aBaseURL) |
659 | 0 | { |
660 | 0 | #ifdef UNX |
661 | 0 | if( aText.startsWith( "~" ) ) |
662 | 0 | { |
663 | 0 | OUString aParseTilde; |
664 | 0 | bool bTrailingSlash = true; // use trailing slash |
665 | |
|
666 | 0 | if( aText.getLength() == 1 || aText[ 1 ] == '/' ) |
667 | 0 | { |
668 | | // covers "~" or "~/..." cases |
669 | 0 | osl_getEnvironment(u"HOME"_ustr.pData, &aParseTilde.pData); |
670 | | |
671 | | // in case the whole path is just "~" then there should |
672 | | // be no trailing slash at the end |
673 | 0 | if( aText.getLength() == 1 ) |
674 | 0 | bTrailingSlash = false; |
675 | 0 | } |
676 | 0 | else |
677 | 0 | { |
678 | | // covers "~username" and "~username/..." cases |
679 | 0 | sal_Int32 nNameEnd = aText.indexOf( '/' ); |
680 | 0 | OUString aUserName = aText.copy( 1, ( nNameEnd != -1 ) ? nNameEnd : ( aText.getLength() - 1 ) ); |
681 | |
|
682 | 0 | struct passwd* pPasswd = nullptr; |
683 | | #ifdef __sun |
684 | | Sequence< sal_Int8 > sBuf( 1024 ); |
685 | | struct passwd aTmp; |
686 | | sal_Int32 nRes = getpwnam_r( OUStringToOString( aUserName, RTL_TEXTENCODING_ASCII_US ).getStr(), |
687 | | &aTmp, |
688 | | (char*)sBuf.getArray(), |
689 | | 1024, |
690 | | &pPasswd ); |
691 | | if( !nRes && pPasswd ) |
692 | | aParseTilde = OUString::createFromAscii(pPasswd->pw_dir); |
693 | | else |
694 | | return false; // no such user |
695 | | #else |
696 | 0 | pPasswd = getpwnam( OUStringToOString( aUserName, RTL_TEXTENCODING_ASCII_US ).getStr() ); |
697 | 0 | if( pPasswd ) |
698 | 0 | aParseTilde = OUString::createFromAscii(pPasswd->pw_dir); |
699 | 0 | else |
700 | 0 | return false; // no such user |
701 | 0 | #endif |
702 | | |
703 | | // in case the path is "~username" then there should |
704 | | // be no trailing slash at the end |
705 | 0 | if( nNameEnd == -1 ) |
706 | 0 | bTrailingSlash = false; |
707 | 0 | } |
708 | | |
709 | 0 | if( !bTrailingSlash ) |
710 | 0 | { |
711 | 0 | if( aParseTilde.isEmpty() || aParseTilde == "/" ) |
712 | 0 | { |
713 | | // "/" path should be converted to "/." |
714 | 0 | aParseTilde = "/."; |
715 | 0 | } |
716 | 0 | else |
717 | 0 | { |
718 | | // "blabla/" path should be converted to "blabla" |
719 | 0 | aParseTilde = comphelper::string::stripEnd(aParseTilde, '/'); |
720 | 0 | } |
721 | 0 | } |
722 | 0 | else |
723 | 0 | { |
724 | 0 | if( !aParseTilde.endsWith("/") ) |
725 | 0 | aParseTilde += "/"; |
726 | 0 | if( aText.getLength() > 2 ) |
727 | 0 | aParseTilde += aText.subView( 2 ); |
728 | 0 | } |
729 | |
|
730 | 0 | aText = aParseTilde; |
731 | 0 | aBaseURL.clear(); // tilde provide absolute path |
732 | 0 | } |
733 | 0 | #endif |
734 | | |
735 | 0 | return true; |
736 | 0 | } |
737 | | |
738 | | //-- |
739 | | |
740 | | OUString SvtURLBox::ParseSmart( const OUString& _aText, const OUString& _aBaseURL ) |
741 | 0 | { |
742 | 0 | OUString aMatch; |
743 | 0 | OUString aText = _aText; |
744 | 0 | OUString aBaseURL = _aBaseURL; |
745 | | |
746 | | // parse ~ for Unix systems |
747 | | // does nothing for Windows |
748 | 0 | if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) ) |
749 | 0 | return OUString(); |
750 | | |
751 | 0 | if( !aBaseURL.isEmpty() ) |
752 | 0 | { |
753 | 0 | INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL ); |
754 | | |
755 | | // if a base URL is set the string may be parsed relative |
756 | 0 | if( aText.startsWith( "/" ) ) |
757 | 0 | { |
758 | | // text starting with slashes means absolute file URLs |
759 | 0 | OUString aTemp = INetURLObject::GetScheme( eBaseProt ); |
760 | | |
761 | | // file URL must be correctly encoded! |
762 | 0 | OUString aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH, |
763 | 0 | INetURLObject::EncodeMechanism::All ); |
764 | 0 | aTemp += aTextURL; |
765 | |
|
766 | 0 | INetURLObject aTmp( aTemp ); |
767 | 0 | if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid ) |
768 | 0 | aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
769 | 0 | } |
770 | 0 | else |
771 | 0 | { |
772 | 0 | OUString aSmart( aText ); |
773 | 0 | INetURLObject aObj( aBaseURL ); |
774 | | |
775 | | // HRO: I suppose this hack should only be done for Windows !!!??? |
776 | | #ifdef _WIN32 |
777 | | // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path |
778 | | // but in case of "\\\\" INetURLObject is right - this is an absolute path ! |
779 | | |
780 | | if( aText.startsWith("\\") && (aText.getLength() < 2 || aText[ 1 ] != '\\') ) |
781 | | { |
782 | | // cut to first segment |
783 | | OUString aTmp = INetURLObject::GetScheme( eBaseProt ) + "/"; |
784 | | aTmp += aObj.getName( 0, true, INetURLObject::DecodeMechanism::WithCharset ); |
785 | | aObj.SetURL( aTmp ); |
786 | | |
787 | | aSmart = aSmart.copy(1); |
788 | | } |
789 | | #endif |
790 | | // base URL must be a directory ! |
791 | 0 | aObj.setFinalSlash(); |
792 | | |
793 | | // take base URL and append current input |
794 | 0 | bool bWasAbsolute = false; |
795 | 0 | #ifdef UNX |
796 | | // encode file URL correctly |
797 | 0 | aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, INetURLObject::EncodeMechanism::All ); |
798 | 0 | #endif |
799 | 0 | INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) ); |
800 | |
|
801 | 0 | if ( aText.endsWith(".") ) |
802 | | // INetURLObject appends a final slash for the directories "." and "..", this is a bug! |
803 | | // Remove it as a workaround |
804 | 0 | aTmp.removeFinalSlash(); |
805 | 0 | if ( !aTmp.HasError() && aTmp.GetProtocol() != INetProtocol::NotValid ) |
806 | 0 | aMatch = aTmp.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
807 | 0 | } |
808 | 0 | } |
809 | 0 | else |
810 | 0 | { |
811 | 0 | OUString aTmpMatch; |
812 | 0 | osl::FileBase::getFileURLFromSystemPath( aText, aTmpMatch ); |
813 | 0 | aMatch = aTmpMatch; |
814 | 0 | } |
815 | |
|
816 | 0 | return aMatch; |
817 | 0 | } |
818 | | |
819 | | IMPL_LINK_NOARG(SvtURLBox, TryAutoComplete, Timer *, void) |
820 | 0 | { |
821 | 0 | OUString aCurText = m_xWidget->get_active_text(); |
822 | 0 | int nStartPos, nEndPos; |
823 | 0 | m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos); |
824 | 0 | if (std::max(nStartPos, nEndPos) != aCurText.getLength()) |
825 | 0 | return; |
826 | | |
827 | 0 | auto nLen = std::min(nStartPos, nEndPos); |
828 | 0 | aCurText = aCurText.copy( 0, nLen ); |
829 | 0 | if (!aCurText.isEmpty()) |
830 | 0 | { |
831 | 0 | if (pCtx.is()) |
832 | 0 | { |
833 | 0 | pCtx->Stop(); |
834 | 0 | pCtx->join(); |
835 | 0 | pCtx.clear(); |
836 | 0 | } |
837 | 0 | pCtx = new SvtMatchContext_Impl(this, aCurText); |
838 | 0 | pCtx->launch(); |
839 | 0 | } |
840 | 0 | else |
841 | 0 | m_xWidget->clear(); |
842 | 0 | } |
843 | | |
844 | | SvtURLBox::SvtURLBox(std::unique_ptr<weld::ComboBox> pWidget) |
845 | 0 | : aChangedIdle("svtools::URLBox aChangedIdle") |
846 | 0 | , eSmartProtocol(INetProtocol::NotValid) |
847 | 0 | , bOnlyDirectories( false ) |
848 | 0 | , bHistoryDisabled( false ) |
849 | 0 | , bNoSelection( false ) |
850 | 0 | , m_xWidget(std::move(pWidget)) |
851 | 0 | { |
852 | | //don't grow to fix mega-long urls |
853 | 0 | Size aSize(m_xWidget->get_preferred_size()); |
854 | 0 | m_xWidget->set_size_request(aSize.Width(), -1); |
855 | |
|
856 | 0 | Init(); |
857 | |
|
858 | 0 | m_xWidget->connect_focus_in(LINK(this, SvtURLBox, FocusInHdl)); |
859 | 0 | m_xWidget->connect_focus_out(LINK(this, SvtURLBox, FocusOutHdl)); |
860 | 0 | m_xWidget->connect_changed(LINK(this, SvtURLBox, ChangedHdl)); |
861 | |
|
862 | 0 | aChangedIdle.SetInvokeHandler(LINK(this, SvtURLBox, TryAutoComplete)); |
863 | 0 | } |
864 | | |
865 | | void SvtURLBox::Init() |
866 | 0 | { |
867 | 0 | pImpl.reset( new SvtURLBox_Impl ); |
868 | |
|
869 | 0 | m_xWidget->set_entry_completion(false); |
870 | |
|
871 | 0 | UpdatePicklistForSmartProtocol_Impl(); |
872 | 0 | } |
873 | | |
874 | | SvtURLBox::~SvtURLBox() |
875 | 0 | { |
876 | 0 | if (pCtx.is()) |
877 | 0 | { |
878 | 0 | pCtx->Stop(); |
879 | 0 | pCtx->join(); |
880 | 0 | } |
881 | 0 | } |
882 | | |
883 | | void SvtURLBox::SetSmartProtocol(INetProtocol eProt) |
884 | 0 | { |
885 | 0 | if ( eSmartProtocol != eProt ) |
886 | 0 | { |
887 | 0 | eSmartProtocol = eProt; |
888 | 0 | UpdatePicklistForSmartProtocol_Impl(); |
889 | 0 | } |
890 | 0 | } |
891 | | |
892 | | void SvtURLBox::UpdatePicklistForSmartProtocol_Impl() |
893 | 0 | { |
894 | 0 | m_xWidget->clear(); |
895 | 0 | if ( bHistoryDisabled ) |
896 | 0 | return; |
897 | | |
898 | 0 | if (bHistoryDisabled) |
899 | 0 | return; |
900 | | |
901 | | // read history pick list |
902 | 0 | const std::vector< SvtHistoryOptions::HistoryItem > seqPicklist = SvtHistoryOptions::GetList( EHistoryType::PickList ); |
903 | 0 | INetURLObject aCurObj; |
904 | |
|
905 | 0 | for( const SvtHistoryOptions::HistoryItem& rPropertySet : seqPicklist ) |
906 | 0 | { |
907 | 0 | aCurObj.SetURL( rPropertySet.sURL ); |
908 | |
|
909 | 0 | if ( !rPropertySet.sURL.isEmpty() && ( eSmartProtocol != INetProtocol::NotValid ) ) |
910 | 0 | { |
911 | 0 | if( aCurObj.GetProtocol() != eSmartProtocol ) |
912 | 0 | continue; |
913 | 0 | } |
914 | | |
915 | 0 | OUString aURL( aCurObj.GetMainURL( INetURLObject::DecodeMechanism::WithCharset ) ); |
916 | |
|
917 | 0 | if ( !aURL.isEmpty() ) |
918 | 0 | { |
919 | 0 | bool bFound = aURL.endsWith("/"); |
920 | 0 | if ( !bFound ) |
921 | 0 | { |
922 | 0 | OUString aUpperURL = aURL.toAsciiUpperCase(); |
923 | |
|
924 | 0 | bFound = ::std::any_of(pImpl->m_aFilters.begin(), |
925 | 0 | pImpl->m_aFilters.end(), |
926 | 0 | FilterMatch( aUpperURL ) ); |
927 | 0 | } |
928 | 0 | if ( bFound ) |
929 | 0 | { |
930 | 0 | OUString aFile; |
931 | 0 | if (osl::FileBase::getSystemPathFromFileURL(aURL, aFile) == osl::FileBase::E_None) |
932 | 0 | m_xWidget->append_text(aFile); |
933 | 0 | else |
934 | 0 | m_xWidget->append_text(aURL); |
935 | 0 | } |
936 | 0 | } |
937 | 0 | } |
938 | 0 | } |
939 | | |
940 | | IMPL_LINK_NOARG(SvtURLBox, ChangedHdl, weld::ComboBox&, void) |
941 | 0 | { |
942 | 0 | aChangeHdl.Call(*m_xWidget); |
943 | 0 | aChangedIdle.Start(); //launch this to happen on idle after cursor position will have been set |
944 | 0 | } |
945 | | |
946 | | IMPL_LINK_NOARG(SvtURLBox, FocusInHdl, weld::Widget&, void) |
947 | 0 | { |
948 | | #ifndef UNX |
949 | | // pb: don't select automatically on unix #93251# |
950 | | m_xWidget->select_entry_region(0, -1); |
951 | | #endif |
952 | 0 | aFocusInHdl.Call(*m_xWidget); |
953 | 0 | } |
954 | | |
955 | | IMPL_LINK_NOARG(SvtURLBox, FocusOutHdl, weld::Widget&, void) |
956 | 0 | { |
957 | 0 | if (pCtx.is()) |
958 | 0 | { |
959 | 0 | pCtx->Stop(); |
960 | 0 | pCtx->join(); |
961 | 0 | pCtx.clear(); |
962 | 0 | } |
963 | 0 | aFocusOutHdl.Call(*m_xWidget); |
964 | 0 | } |
965 | | |
966 | | void SvtURLBox::SetOnlyDirectories( bool bDir ) |
967 | 0 | { |
968 | 0 | bOnlyDirectories = bDir; |
969 | 0 | if ( bOnlyDirectories ) |
970 | 0 | m_xWidget->clear(); |
971 | 0 | } |
972 | | |
973 | | void SvtURLBox::SetNoURLSelection( bool bSet ) |
974 | 0 | { |
975 | 0 | bNoSelection = bSet; |
976 | 0 | } |
977 | | |
978 | | OUString SvtURLBox::GetURL() |
979 | 0 | { |
980 | | // wait for end of autocompletion |
981 | 0 | ::osl::MutexGuard aGuard( theSvtMatchContextMutex() ); |
982 | |
|
983 | 0 | OUString aText(m_xWidget->get_active_text()); |
984 | 0 | if (MatchesPlaceHolder(aText)) |
985 | 0 | return aPlaceHolder; |
986 | | |
987 | | // try to get the right case preserving URL from the list of URLs |
988 | 0 | for(std::vector<OUString>::iterator i = pImpl->aCompletions.begin(), j = pImpl->aURLs.begin(); i != pImpl->aCompletions.end() && j != pImpl->aURLs.end(); ++i, ++j) |
989 | 0 | { |
990 | 0 | if((*i) == aText) |
991 | 0 | return *j; |
992 | 0 | } |
993 | | |
994 | | #ifdef _WIN32 |
995 | | // erase trailing spaces on Windows since they are invalid on this OS and |
996 | | // most of the time they are inserted by accident via copy / paste |
997 | | aText = comphelper::string::stripEnd(aText, ' '); |
998 | | if ( aText.isEmpty() ) |
999 | | return aText; |
1000 | | // #i9739# |
1001 | | #endif |
1002 | | |
1003 | 0 | INetURLObject aObj( aText ); |
1004 | 0 | if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 ) |
1005 | 0 | { |
1006 | | // no autocompletion for wildcards |
1007 | 0 | INetURLObject aTempObj; |
1008 | 0 | if ( eSmartProtocol != INetProtocol::NotValid ) |
1009 | 0 | aTempObj.SetSmartProtocol( eSmartProtocol ); |
1010 | 0 | if ( aTempObj.SetSmartURL( aText ) ) |
1011 | 0 | return aTempObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
1012 | 0 | else |
1013 | 0 | return aText; |
1014 | 0 | } |
1015 | | |
1016 | 0 | if ( aObj.GetProtocol() == INetProtocol::NotValid ) |
1017 | 0 | { |
1018 | 0 | OUString aName = ParseSmart( aText, aBaseURL ); |
1019 | 0 | aObj.SetURL(aName); |
1020 | 0 | OUString aURL( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); |
1021 | 0 | if ( aURL.isEmpty() ) |
1022 | | // aText itself is invalid, and even together with aBaseURL, it could not |
1023 | | // made valid -> no chance |
1024 | 0 | return aText; |
1025 | | |
1026 | 0 | bool bSlash = aObj.hasFinalSlash(); |
1027 | 0 | { |
1028 | 0 | OUString aFileURL; |
1029 | |
|
1030 | 0 | Any aAny = UCBContentHelper::GetProperty(aURL, u"CasePreservingURL"_ustr); |
1031 | 0 | bool success = (aAny >>= aFileURL); |
1032 | 0 | OUString aTitle; |
1033 | 0 | if(success) |
1034 | 0 | aTitle = INetURLObject(aFileURL).getName( |
1035 | 0 | INetURLObject::LAST_SEGMENT, |
1036 | 0 | true, |
1037 | 0 | INetURLObject::DecodeMechanism::WithCharset ); |
1038 | 0 | else |
1039 | 0 | success = |
1040 | 0 | UCBContentHelper::GetTitle(aURL,&aTitle); |
1041 | |
|
1042 | 0 | if( success && aTitle != "/" && aTitle != "." ) |
1043 | 0 | { |
1044 | 0 | aObj.setName( aTitle ); |
1045 | 0 | if ( bSlash ) |
1046 | 0 | aObj.setFinalSlash(); |
1047 | 0 | } |
1048 | 0 | } |
1049 | 0 | } |
1050 | | |
1051 | 0 | return aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); |
1052 | 0 | } |
1053 | | |
1054 | | void SvtURLBox::SetBaseURL( const OUString& rURL ) |
1055 | 0 | { |
1056 | 0 | ::osl::MutexGuard aGuard( theSvtMatchContextMutex() ); |
1057 | | |
1058 | | // Reset match lists |
1059 | 0 | pImpl->aCompletions.clear(); |
1060 | 0 | pImpl->aURLs.clear(); |
1061 | |
|
1062 | 0 | aBaseURL = rURL; |
1063 | 0 | } |
1064 | | |
1065 | | void SvtURLBox::DisableHistory() |
1066 | 0 | { |
1067 | 0 | bHistoryDisabled = true; |
1068 | 0 | UpdatePicklistForSmartProtocol_Impl(); |
1069 | 0 | } |
1070 | | |
1071 | | void SvtURLBox::SetFilter(std::u16string_view _sFilter) |
1072 | 0 | { |
1073 | 0 | pImpl->m_aFilters.clear(); |
1074 | 0 | FilterMatch::createWildCardFilterList(_sFilter,pImpl->m_aFilters); |
1075 | 0 | } |
1076 | | |
1077 | | void FilterMatch::createWildCardFilterList(std::u16string_view _rFilterList,::std::vector< WildCard >& _rFilters) |
1078 | 0 | { |
1079 | 0 | if( !_rFilterList.empty() ) |
1080 | 0 | { |
1081 | | // filter is given |
1082 | 0 | sal_Int32 nIndex = 0; |
1083 | 0 | OUString sToken; |
1084 | 0 | do |
1085 | 0 | { |
1086 | 0 | sToken = o3tl::getToken(_rFilterList, 0, ';', nIndex ); |
1087 | 0 | if ( !sToken.isEmpty() ) |
1088 | 0 | { |
1089 | 0 | _rFilters.emplace_back( sToken.toAsciiUpperCase() ); |
1090 | 0 | } |
1091 | 0 | } |
1092 | 0 | while ( nIndex >= 0 ); |
1093 | 0 | } |
1094 | 0 | else |
1095 | 0 | { |
1096 | | // no filter is given -> match all |
1097 | 0 | _rFilters.emplace_back(u"*" ); |
1098 | 0 | } |
1099 | 0 | } |
1100 | | |
1101 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |