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