MauiKit File Browsing

FileDialog.qml
1/*
2 * Copyright 2018 Camilo Higuita <milo.h@aol.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick
21import QtQml
22
23import QtQuick.Controls
24import QtQuick.Layouts
25
26import org.mauikit.controls as Maui
27import org.mauikit.filebrowsing as FB
28
29/**
30 * @inherit org::mauikit::controls::PopupPage
31 *
32 * @brief A dialog to quickly select files for opening or saving.
33 *
34 * This controls inherits from MauiKit PopupPage, to checkout its inherited properties refer to the docs.
35 * @see MauiKit::PopupPage
36 *
37 * @note This component makes use of the FileBrowser.
38 *
39 * The FileDialog can be in two modes, one for Opening and other for Saving files.
40 *
41 * The file dialog allows to have multiple or single selection,
42 * and filtering content specific to a file type or arbitrary name filters.
43 *
44 * @image html filedialog.png
45 *
46 * @code
47 * Maui.Page
48 * {
49 * Maui.Controls.showCSD: true
50 * anchors.fill: parent
51 *
52 * Column
53 * {
54 * width: 100
55 * anchors.centerIn: parent
56 *
57 * Button
58 * {
59 * text: "Open"
60 * onClicked:
61 * {
62 * _dialog.mode = FB.FileDialog.Modes.Open
63 * _dialog.callback = (paths) =>
64 * {
65 * console.log("Selected Paths", paths)
66 * _text.text = paths.join("\n")
67 * }
68 * _dialog.open()
69 * }
70 * }
71 *
72 * Button
73 * {
74 * text: "Save"
75 * onClicked:
76 * {
77 * _dialog.mode = FB.FileDialog.Modes.Save
78 * _dialog.callback = (paths) =>
79 * {
80 * console.log("Save to", paths)
81 * _text.text = paths.join("\n")
82 * }
83 * _dialog.open()
84 * }
85 * }
86 *
87 * Text
88 * {
89 * id: _text
90 * }
91 * }
92 * }
93 *
94 * FB.FileDialog
95 * {
96 * id: _dialog
97 * }
98 * @endcode
99 *
100 * <a href="https://invent.kde.org/maui/mauikit-filebrowser/examples/FileDialog.qml">You can find a more complete example at this link.</a>
101 */
102Maui.PopupPage
103{
104 id: control
105
106 maxHeight: Maui.Handy.isMobile ? parent.height * 0.95 : 500
107 maxWidth: 700
108
109 hint: 1
111 page.padding: 0
112 closeButtonVisible: false
113 headBar.visible: false
114
115 /**
116 * @brief The current path of the directory URL.
117 * @see FileBrowser::currentPath
118 */
119 property alias currentPath : _browser.currentPath
120
121 /**
122 * @brief The FileBrowser used for listing.
123 * For more details on how it works check its documentation.
124 * @property FileBrowser FileDialog::browser
125 */
126 readonly property alias browser : _browser
127
128 /**
129 * @see FileBrowser::selectionBar
130 * This control already has a predefined SelectionBar, and can be accessed via this alias.
131 * @property MauiKit::SelectionBar FileDialog::selectionBar
132 */
133 readonly property alias selectionBar: _selectionBar
135 /**
136 * @brief If true then only one item can be selected, either for saving or for opening.
137 * @property bool FileDialog::singleSelection
138 */
139 property alias singleSelection : _selectionBar.singleSelection
140
141 /**
142 * @brief On save mode a text field is visible and this property is used to assign its default text value.
143 * By default this is set to empty string
144 */
145 property string suggestedFileName : ""
146
147 /**
148 * @brief Show the search bar to enter a search query.
149 */
150 property bool searchBar : false
151 onSearchBarChanged: if(!searchBar) _browser.quitSearch()
152
153 /**
154 * @brief The two different modes to use with this dialog.
155 */
156 enum Modes
157 {
158 /**
159 * To use this dialog for selecting one or multiple entries for opening.
160 */
161 Open,
162
163 /**
164 * To use this dialog to select a single directory where to save a file entry with a given name.
165 */
166 Save
168
169 /**
170 * @brief The current mode in use.
171 * By default this is set to `FileDialog.Modes.Open`
172 * @see Modes
173 */
174 property int mode : FileDialog.Modes.Open
175
176 /**
177 * @brief A callback function that will be invoked once the user is done selecting the files.
178 * This is useful when the file dialog is going to be used for multiple purposes.
179 * Otherwise you might want to use the `urlsSelected` signal.
180 * @see urlsSelected
181 */
182 property var callback
183
184 /**
185 * @brief On Save mode a text field is visible, this property gives access to it.
186 */
187 readonly property alias textField: _textField
188
189 /**
190 * @brief Emitted once the URLs have been selected.
191 * @param urls the selected list of URLs
192 */
193 signal urlsSelected(var urls)
194
195 /**
196 * @brief Emitted once the selection has been done.
197 * @param urls the selected list of URLs
198 */
199 signal finished(var urls)
200
201 actions:
202 [
203 Action
204 {
205 text: i18nd("mauikitfilebrowsing", "Cancel")
206 onTriggered: control.close()
207 },
208
209 Action
210 {
211 text: control.mode === FileDialog.Modes.Save ? i18nd("mauikitfilebrowsing", "Save") : i18nd("mauikitfilebrowsing", "Open")
212 Maui.Controls.status: Maui.Controls.Positive
213 onTriggered:
214 {
215 console.log("CURRENT PATHb", _browser.currentPath+"/"+textField.text)
216 if(control.mode === FileDialog.Modes.Save && textField.text.length === 0)
217 return
218
219 if(control.mode === FileDialog.Modes.Save && FB.FM.fileExists(_browser.currentPath+"/"+textField.text))
220 {
221 _confirmationDialog.open()
222 }else
223 {
224 done()
225 }
226 }
227 }
228 ]
229
230 page.footerColumn: [
231
232 Maui.ToolBar
233 {
234 visible: control.mode === FileDialog.Modes.Save
235 width: parent.width
236 position: ToolBar.Footer
237
238 middleContent: TextField
239 {
240 id: _textField
241 Layout.fillWidth: true
242 placeholderText: i18nd("mauikitfilebrowsing", "File name...")
243 text: suggestedFileName
244 }
245 }
246 ]
247
248 Maui.InfoDialog
249 {
250 id: _confirmationDialog
251
252 title: i18nd("mauikitfilebrowsing", "Error")
253 message: i18nd("mauikitfilebrowsing", "A file named '%1' already exists!\n This action will overwrite '%1'. Are you sure you want to do this?", control.textField.text)
254 template.iconSource: "dialog-warning"
255
256 standardButtons: Dialog.Ok | Dialog.Cancel
257
258 onAccepted: control.done()
259 onRejected: close()
260 }
261
262 stack: Maui.SideBarView
263 {
264 id: pageRow
265
266 Layout.fillHeight: true
267 Layout.fillWidth: true
268
269 sideBar.preferredWidth: 200
270 sideBar.minimumWidth: 200
271 sideBarContent: Loader
272 {
273 id: sidebarLoader
274 asynchronous: true
275 anchors.fill: parent
276
277 sourceComponent: FB.PlacesListBrowser
278 {
279 onPlaceClicked: (path) =>
280 {
281 //pageRow.currentIndex = 1
282 _browser.openFolder(path)
283 }
284
285 currentPath: _browser.currentPath
286
287 list.groups: [
288 FB.FMList.BOOKMARKS_PATH,
289 FB.FMList.REMOTE_PATH,
290 FB.FMList.CLOUD_PATH,
291 FB.FMList.DRIVES_PATH]
292 }
293 }
294
295 Maui.Page
296 {
297 id: _browserLayout
298 anchors.fill: parent
299
300 floatingFooter: true
301 flickable: _browser.flickable
302 headBar.visible: true
303 headerColorSet: Maui.Theme.Header
304 headBar.farLeftContent: ToolButton
305 {
306 icon.name: pageRow.sideBar.visible ? "sidebar-collapse" : "sidebar-expand"
307 onClicked: pageRow.sideBar.toggle()
308 checked: pageRow.sideBar.visible
309 ToolTip.delay: 1000
310 ToolTip.timeout: 5000
311 ToolTip.visible: hovered
312 ToolTip.text: i18nd("mauikitfilebrowsing", "Toogle SideBar")
313 }
314
315 headBar.rightContent:[
316
317 ToolButton
318 {
319 id: searchButton
320 icon.name: "edit-find"
321 onClicked: browser.toggleSearchBar()
322 checked: browser.headBar.visible
323 },
324
325 Loader
326 {
327 asynchronous: true
328 sourceComponent: Maui.ToolButtonMenu
329 {
330 icon.name: browser.settings.viewType === FB.FMList.LIST_VIEW ? "view-list-details" : "view-list-icons"
331
332 Maui.MenuItemActionRow
333 {
334 Action
335 {
336 icon.name: "view-hidden"
337 // text: i18nd("mauikitfilebrowsing", "Hidden Files")
338 checkable: true
339 checked: browser.settings.showHiddenFiles
340 onTriggered: browser.settings.showHiddenFiles = !browser.settings.showHiddenFiles
341 }
342
343 Action
344 {
345 icon.name: "folder-new"
346 onTriggered: browser.newItem()
347 }
348 }
349
350 Maui.LabelDelegate
351 {
352 width: parent.width
353 isSection: true
354 text: i18nd("mauikitfilebrowsing", "View type")
355 }
356
357 Action
358 {
359 text: i18nd("mauikitfilebrowsing", "List")
360 icon.name: "view-list-details"
361 checked: browser.settings.viewType === FB.FMList.LIST_VIEW
362 checkable: true
363 onTriggered:
364 {
365 if(browser)
366 {
367 browser.settings.viewType = FB.FMList.LIST_VIEW
368 }
369 }
370 }
371
372 Action
373 {
374 text: i18nd("mauikitfilebrowsing", "Grid")
375 icon.name: "view-list-icons"
376 checked: browser.settings.viewType === FB.FMList.ICON_VIEW
377 checkable: true
378
379 onTriggered:
380 {
381 if(browser)
382 {
383 browser.settings.viewType = FB.FMList.ICON_VIEW
384 }
385 }
386 }
387
388 MenuSeparator {}
389
390 Maui.LabelDelegate
391 {
392 width: parent.width
393 isSection: true
394 text: i18nd("mauikitfilebrowsing", "Sort by")
395 }
396
397 Action
398 {
399 text: i18nd("mauikitfilebrowsing", "Type")
400 checked: browser.settings.sortBy === FB.FMList.MIME
401 checkable: true
402
403 onTriggered:
404 {
405 browser.settings.sortBy = FB.FMList.MIME
406 }
407 }
408
409 Action
410 {
411 text: i18nd("mauikitfilebrowsing", "Date")
412 checked: browser.settings.sortBy === FB.FMList.DATE
413 checkable: true
414
415 onTriggered:
416 {
417 browser.settings.sortBy = FB.FMList.DATE
418 }
419 }
420
421 Action
422 {
423 text: i18nd("mauikitfilebrowsing", "Modified")
424 checked: browser.settings.sortBy === FB.FMList.MODIFIED
425 checkable: true
426
427 onTriggered:
428 {
429 browser.settings.sortBy = FB.FMList.MODIFIED
430 }
431 }
432
433 Action
434 {
435 text: i18nd("mauikitfilebrowsing", "Size")
436 checked: browser.settings.sortBy === FB.FMList.SIZE
437 checkable: true
438
439 onTriggered:
440 {
441 browser.settings.sortBy = FB.FMList.SIZE
442 }
443 }
444
445 Action
446 {
447 text: i18nd("mauikitfilebrowsing", "Name")
448 checked: browser.settings.sortBy === FB.FMList.LABEL
449 checkable: true
450
451 onTriggered:
452 {
453 browser.settings.sortBy = FB.FMList.LABEL
454 }
455 }
456
457 MenuSeparator{}
458
459 MenuItem
460 {
461 text: i18nd("mauikitfilebrowsing", "Show Folders First")
462 checked: browser.settings.foldersFirst
463 checkable: true
464
465 onTriggered:
466 {
467 browser.settings.foldersFirst = !browser.settings.foldersFirst
468 }
469 }
470
471 MenuItem
472 {
473 id: groupAction
474 text: i18nd("mauikitfilebrowsing", "Group")
475 checkable: true
476 checked: browser.settings.group
477 onTriggered:
478 {
479 browser.settings.group = !browser.settings.group
480 }
481 }
482 }
483 }
484 ]
485
486 headBar.leftContent: Loader
487 {
488 asynchronous: true
489 sourceComponent: Maui.ToolActions
490 {
491 expanded: true
492 autoExclusive: false
493 checkable: false
494
495 Action
496 {
497 icon.name: "go-previous"
498 onTriggered : browser.goBack()
499 }
500
501 Action
502 {
503 icon.name: "go-up"
504 onTriggered : browser.goUp()
505 }
506
507 Action
508 {
509 icon.name: "go-next"
510 onTriggered: browser.goNext()
511 }
512 }
513 }
514
515 footer: Maui.SelectionBar
516 {
517 id: _selectionBar
518
519 anchors.horizontalCenter: parent.horizontalCenter
520 width: Math.min(parent.width-(Maui.Style.space.medium*2), implicitWidth)
521 maxListHeight: control.height - (Maui.Style.contentMargins*2)
522
523 listDelegate: Maui.ListBrowserDelegate
524 {
525 width: ListView.view.width
526 iconSource: model.icon
527 imageSource: model.thumbnail
528 label1.text: model.label
529 label2.text: model.url
530 }
531
532 onExitClicked:
533 {
534 _selectionBar.clear()
535 }
536 }
537
538 FB.FileBrowser
539 {
540 id: _browser
541 anchors.fill: parent
542
543 selectionBar: _selectionBar
544 settings.viewType: FB.FMList.LIST_VIEW
545 currentPath: FB.FM.homePath()
546 selectionMode: control.mode === FileDialog.Modes.Open
547 onItemClicked: (index) =>
548 {
549 if(Maui.Handy.singleClick)
550 {
551 performAction(index)
552 }
553 }
554
555 onItemDoubleClicked: (index) =>
556 {
557 if(!Maui.Handy.singleClick)
558 {
559 performAction(index)
560 }
561 }
562
563 function performAction(index)
564 {
565 if(currentFMModel.get(index).isdir == "true")
566 {
567 openItem(index)
568 }
569
570 switch(control.mode)
571 {
572 case FileDialog.Modes.Open :
573 addToSelection(currentFMModel.get(index))
574 break;
575
576 case FileDialog.Modes.Save:
577 textField.text = currentFMModel.get(index).label
578 break;
579 }
580 }
581 }
582 }
583 }
584
585 onClosed:
586 {
587 _selectionBar.clear()
588 }
589
590 /**
591 * @private
592 */
593 function done()
594 {
595 var paths = _browser.selectionBar && _browser.selectionBar.visible ? _browser.selectionBar.uris : [_browser.currentPath]
596
597 if(control.mode === FileDialog.Modes.Save)
598 {
599 for(var i in paths)
600 {
601 paths[i] = paths[i] + "/" + textField.text
602 }
603
604 // _tagsBar.list.urls = paths
605 // _tagsBar.list.updateToUrls(_tagsBar.getTags())
606 }
607
608 control.finished(paths)
609
610 // if(control.mode === modes.SAVE) //do it after finished in cas ethe files need to be saved aka exists, before tryign to insert tags
611 // {
612 // _tagsBar.list.urls = paths
613 // _tagsBar.list.updateToUrls(_tagsBar.getTags())
614 // }
615
616 if(control.callback)
617 {
618 control.callback(paths)
619 }
620
621 control.urlsSelected(paths)
622 control.close()
623 }
624}
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:32:33 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.