Merge lp:~jeremywootten/pantheon-files/all-views-vala into lp:~elementary-apps/pantheon-files/trunk
- all-views-vala
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Danielle Foré |
Approved revision: | 1661 |
Merged at revision: | 1643 |
Proposed branch: | lp:~jeremywootten/pantheon-files/all-views-vala |
Merge into: | lp:~elementary-apps/pantheon-files/trunk |
Diff against target: |
49548 lines (+17157/-29587) 96 files modified
.bzrignore (+1/-1) AUTHORS (+2/-0) CMakeLists.txt (+1/-1) data/schemas/org.pantheon.files.gschema.xml (+2/-2) libcore/AbstractSlot.vala (+76/-0) libcore/CMakeLists.txt (+3/-2) libcore/Plugin.vala (+1/-1) libcore/PluginManager.vala (+1/-1) libcore/eel-stock-dialogs.c (+0/-3) libcore/fm-list-model.c (+60/-139) libcore/fm-list-model.h (+3/-9) libcore/gof-abstract-slot.c (+0/-47) libcore/gof-abstract-slot.h (+0/-56) libcore/gof-directory-async.vala (+45/-23) libcore/gof-file.c (+46/-26) libcore/gof-file.h (+4/-3) libcore/marlin-file-changes-queue.c (+0/-3) libcore/marlin-file-operations.c (+6/-10) libcore/marlin-icon-info.c (+9/-5) libcore/pantheon-files-core-C.vapi (+86/-16) libwidgets/Animations.vala (+12/-3) libwidgets/BreadcrumbsElements.vala (+1/-1) libwidgets/LocationBar.vala (+15/-13) plugins/network-places/plugin.vala (+12/-7) plugins/pantheon-files-ctags/plugin.vala (+183/-55) plugins/pantheon-files-trash/plugin.vala (+19/-15) src/AbstractEditableLabel.vala (+96/-0) src/Application.vala (+47/-76) src/BookmarkList.vala (+5/-0) src/CMakeLists.txt (+26/-20) src/DndHandler.vala (+272/-0) src/MimeActions.vala (+19/-11) src/MultiLineEditableLabel.vala (+196/-0) src/SingleLineEditableLabel.vala (+104/-0) src/TextRenderer.vala (+307/-0) src/View/AbstractDirectoryView.vala (+2778/-0) src/View/AbstractTreeView.vala (+280/-0) src/View/Browser.vala (+3/-18) src/View/Chrome/ColorWidget.vala (+0/-183) src/View/Chrome/TopMenu.vala (+81/-35) src/View/Chrome/ViewSwicher.vala (+36/-27) src/View/ColumnView.vala (+140/-0) src/View/DbusTags.vala (+0/-100) src/View/DirectoryNotFound.vala (+1/-1) src/View/IconView.vala (+318/-0) src/View/ListView.vala (+235/-0) src/View/LocationBar.vala (+27/-44) src/View/Miller.vala (+396/-0) src/View/OverlayBar.vala (+58/-53) src/View/PropertiesWindow.vala (+5/-4) src/View/Resources.vala (+4/-1) src/View/Sidebar.vala (+44/-40) src/View/Slot.vala (+276/-0) src/View/ViewContainer.vala (+246/-296) src/View/ViewMode.vala (+0/-17) src/View/Window.vala (+614/-604) src/View/directory_view_popup.ui (+138/-0) src/eel-editable-label.c (+0/-4417) src/eel-editable-label.h (+0/-146) src/exo-icon-view.c (+0/-11753) src/exo-icon-view.h (+0/-347) src/exo-tree-view.c (+0/-674) src/exo-tree-view.h (+0/-91) src/fm-abstract-icon-view.c (+0/-870) src/fm-abstract-icon-view.h (+0/-60) src/fm-columns-view.c (+0/-858) src/fm-columns-view.h (+0/-60) src/fm-directory-view-ui.xml (+0/-194) src/fm-directory-view.c (+0/-4059) src/fm-directory-view.h (+0/-446) src/fm-icon-view-ui.xml (+0/-37) src/fm-icon-view.c (+0/-147) src/fm-icon-view.h (+0/-51) src/fm-list-view.c (+0/-999) src/fm-list-view.h (+0/-60) src/gof-window-slot.c (+0/-315) src/gof-window-slot.h (+0/-88) src/gtk+-3.0.deps (+7/-0) src/gtk+-3.0.vapi (+9698/-0) src/main.vala (+1/-0) src/marlin-cell-renderer-text-ellipsized.c (+0/-73) src/marlin-cell-renderer-text-ellipsized.h (+0/-58) src/marlin-clipboard-manager.c (+10/-0) src/marlin-clipboard-manager.h (+3/-0) src/marlin-dnd.c (+0/-230) src/marlin-dnd.h (+0/-43) src/marlin-enum-types.h (+2/-4) src/marlin-global-preferences.h (+1/-0) src/marlin-icon-renderer.c (+13/-4) src/marlin-text-renderer.c (+0/-869) src/marlin-text-renderer.h (+0/-76) src/marlin-view-window.h (+25/-13) src/marlin-window-columns.c (+0/-310) src/marlin-window-columns.h (+0/-84) src/marlin.vapi (+57/-104) src/pantheon-files-ui.xml (+0/-75) |
To merge this branch: | bzr merge lp:~jeremywootten/pantheon-files/all-views-vala |
Related bugs: |
|
Related blueprints: |
Use as much as possible Vala
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PerfectCarl (community) | Approve | ||
Danielle Foré | ux | Approve | |
Jeremy Wootten | Pending | ||
Cody Garver | Pending | ||
Review via email: mp+240371@code.launchpad.net |
This proposal supersedes a proposal from 2014-09-18.
Commit message
* Convert Slot, Miller, DirectoryView, ListView, ColumnView and IconView to Vala.
* Use standard Gtk.TreeView and Gtk.IconView
* Address a number of bugs associated with the views.
* Some changes made to ViewContainer - new slots only made when view mode changes, not when location changes.
* For improved accessibility, helper emblem appears in all views but only when the icons are above a minimum size.
* Implemented bookmarking from context menu
* Implemented "Open in New Window" in context menu
* Context menu and app menu reimplemented without deprecated code.
Description of the change
Convert Slot, Miller, DirectoryView, ListView, ColumnView and IconView to Vala.
Use standard Gtk.TreeView and Gtk.IconView
Address a number of bugs associated with the views.
Some changes made to ViewContainer - new slots only made when view mode changes, not when location changes.
Use of standard Gtk widgets means that multi-item dragging is only possible with the secondary button or by using primary button in combination with a modifier key.
Automatic switching to icon-view in certain directories not (yet) implemented. Is this desirable?
Rename by clicking on name implemented. Is this desirable?
In list and column view, right clicking on any blank space treats it as background allowing operations on root directory even when window filled with rows. Blank space click initiates rubber-banding, not drag.
For improved accessibility, helper emblem appears in all views but only when the icons are above a minimum size. Is this desirable?
Items activate only when clicked on icon. Clicking on name starts on renaming, clicking on blank space selects only. Is this desirable?
Implemented bookmarking from context menu
Implemented "Open in New Window" in context menu
Context menu and app menu reimplemented without deprecated code.
Design input required
Code will be cleaned up before merge
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
I can't appear to open anything (file or folder) in the column view other than the first folder. Clicking another folder selects and opens the top folder.
clicking the object to go in and the title to rename seems to be a lot less awesome in the column and list view where the actual icon is very small. In these views, I would expect clicking empty rows or the title to still open the directory.
I like the way the list view is intelligent about which context menu to pull up depending on where you click.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
I also get a "Run" menu item on folders which appears to do nothing.
Cody Garver (codygarver) wrote : Posted in a previous version of this proposal | # |
Nodes in Entire Network should not be editable
The "Empty Trash" button is sorta selected on hover. It's not bad but I don't know if it's desired by design.
Cody Garver (codygarver) wrote : Posted in a previous version of this proposal | # |
Disregard what I said about Empty Trash, apparently it already behaved like that in trunk
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
I don't get the I-beam cursor anymore. But I also don't get it when hovering a file/folder name. If we get the cursor showing properly, I wonder if we really need to have a menu item for this.
The way labels are wrapped in the icon view is kind of weird. I'm getting stuff like "Document \n s"
I think the Open/Open in/Open with items should be back at the top of the context menu.
I'm now unable to drag and drop any items in icon view.
Items open on click instead of on release.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
Labels in icon view seem to be centered vertically instead of aligned to the top.
Whenever I select something using an emblem, it launches
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
typing to select a folder/file in a directory no longer works
Shawn McTear (syst3mfailur3) wrote : Posted in a previous version of this proposal | # |
> I don't get the I-beam cursor anymore. But I also don't get it when hovering a
> file/folder name. If we get the cursor showing properly, I wonder if we really
> need to have a menu item for this.
>
If the menu item for renaming is removed, maybe adding a tooltip when hovering over the file/folder name to also specify that its editable would be a good idea.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> typing to select a folder/file in a directory no longer works
It should be working in list and column views. It is not working in icon view because Gtk.IconView does not support it - another unforeseen side-effect of switching.
It is possible to apparently 'lock up' the function in list and column view by pressing a second key, creating a non-existent filename, very quickly, before the overlay appears. You have to click on the view again to restart it. This occurs in trunk as well.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> I don't get the I-beam cursor anymore. But I also don't get it when hovering a
> file/folder name. If we get the cursor showing properly, I wonder if we really
> need to have a menu item for this.
>
> The way labels are wrapped in the icon view is kind of weird. I'm getting
> stuff like "Document \n s"
>
> I think the Open/Open in/Open with items should be back at the top of the
> context menu.
>
> I'm now unable to drag and drop any items in icon view.
>
> Items open on click instead of on release.
The cursor doesn't change over the filenames in trunk, but I can try and arrange this.
Items were intended to open on click unless a drag is started - it was working - I'll look into this regression.
I'll address the formating issues you mention
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
Let's kill the font zoom thing. We can discuss that in another branch. In the interest of making a review as easy as possible, I think we should avoid introducing new features in this branch. I think it'd be better to keep the diff as small as possible.
Not being able to type to find a file in the directory is a pretty big regression.
Also, Ctrl + F to search seems to not work again
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
OK, no problem - I'll revert the font zooming in the next revision. Sorry about the re-regression with Ctrl + F, I didn't notice that. I'll not be able to work on this for a couple of days though.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
Looks like I also can't copy folders
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
When you rename something, the name isn't save on lose focus. It's only saved if you press enter.
We should truncate (ellipsis in the center) file/folder names after like 3 lines.
Clicking the title to rename seems to be broken. On releasing the button the entry loses focus
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
The click-to-rename area seems to extend the height of whatever the tallest label is. I'm not sure this is good as it means you can't start a rubberband from a seemingly blank space
Sam Hewitt (snwh) wrote : Posted in a previous version of this proposal | # |
I've found a few regressions with this branch as well:
1. The navigation arrows are not using their symbolic variants.
2. Long folder/file strings seem to be cut off.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Revision 1564 fixes:
Name saved when focus lost during renaming
Single click to rename
Does not rename when click on blank part of name in icon view
The cursor changes when over the editable part of the name label
The height of the name label is limited to three lines.
The following problems remain due mainly to limitations of the Gtk.IconView:
Rubberbanding is not initiated by clicking on the blank part of the name renderer (unlike in Gtk.TreeView)
The editable widget used by Gtk.Iconview is a simple one line Entry which is limited in size to the width of the items in the view. This causes only part of the name to be visible when renaming.
The default Gtk.CellRendere
To solve these issues will probably meaning implementing our own rubberbanding and name renderer and editable widget.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> I've found a few regressions with this branch as well:
>
> 1. The navigation arrows are not using their symbolic variants.
> 2. Long folder/file strings seem to be cut off.
1. OK, will change.
2. Which view are you referring to? Do you mean during renaming? In Column view there is a maximum width set for autosizing which could cause truncation of long names but the limit can be exceeded manually.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Revision 1566 is an attempt to give visual feedback by means of the cursor on the effect of (primary) clicking at the cursor position. In particular this helps in icon view to distinguish the blank area in the name label (no rubberbanding) from the blank space between the items (will rubberband). A different cursor is also used depending on whether clicking (or double clicking) will activate the item or just select it.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
It sounds like there's going to be a *lot* of work to get the views back to where the exo views are.
Is it possible to split this into multiple merges so we can at least get some of your work merged in?
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> It sounds like there's going to be a *lot* of work to get the views back to
> where the exo views are.
>
> Is it possible to split this into multiple merges so we can at least get some
> of your work merged in?
I wish! I originally was going to change one file to Vala but could get it to work without changing another file to Vala and that wouldn't work without changing ... etc. I was hoping that it would be possible to use the Gtk TreeView and IconView widgets to produce something usable even if not exactly the same as the Exo views. This would make the code lighter and easier to maintain. The Gtk IconView is the main problem - it needs a lot of customisation to behave like the exo view, although it would still be easier (probably) than converting the Exo IconView (ca 12000 lines of code) to Vala.
I will have another look at getting the Exo IconView to work in this branch but it would need some new functions.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
The last two revisions implement much of the functionality of the original customised text renderer and editable label but using Vala to create customised Gtk.CellRendere
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
[ 39%] Built target pantheon-
make[2]: *** No rule to make target `../src/
make[1]: *** [src/CMakeFiles
make: *** [all] Error 2
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Oops - sorry - forgot to add the new file to bzr.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
When you drag something over a folder, it changes to the "folder-
If you put the label in edit mode, then click away, the label text will still be selected.
Is there a way to remove that blue coloration from selected items since you already have the grey box?
Cody Garver (codygarver) wrote : Posted in a previous version of this proposal | # |
* Should be "elementary Developers" not "Elementary Developers"
* Warnings:
src/TextRendere
public override void get_size (Gtk.Widget widget, Gdk.Rectangle? cell_area, out int x_offset, out int y_offset, out int width, out int height) {
src/TextRendere
public override void get_size (Gtk.Widget widget, Gdk.Rectangle? cell_area, out int x_offset, out int y_offset, out int width, out int height) {
Cody Garver (codygarver) wrote : Posted in a previous version of this proposal | # |
There are .vala files listed in the .bzrignore
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
The last five revisions address the follow issues:
1) Rubberbanding from any visually blank area on Icon view
2) Drop highlighting works correctly according to whether the target has write permissions and unhighlights correctly
3) Compilation warnings removed
4) .bzrignore files removed
5) When editing a long file name a smaller font is used if it would not otherwise fit in the available area.
6) Ctrl-Z restores original file name during renaming (but does not end rename)
7) Folder names with dots are fully selected during rename
8) ViewContainer now correctly forgets selected files after selecting them after a view change.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
9) Editable widget correctly hides when loses focus
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
A number of other bugs/wish-list items have now been fixed.
Cody Garver (codygarver) wrote : Posted in a previous version of this proposal | # |
I get a target reticle cursor when I'm not hovering over a file in Grid view
Right click > Copy is grayed out for me for every file in Grid view
Some, seemingly random files are italicized in Grid view
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> I get a target reticle cursor when I'm not hovering over a file in Grid view
>
> Right click > Copy is grayed out for me for every file in Grid view
>
> Some, seemingly random files are italicized in Grid view
The target reticle cursor is used to indicate that rubberbanding is active. The arrow cursor indicates that selection (or row expansion) will occur but not activation. The hand cursor indicates activation will occur, the I-bar cursor indicates that renaming will occur.
It will be a design team decision whether any of this cursor shape feedback is necessary or desirable - it is easily disabled.
The italicized filenames indicate that you do not have write permission for the file and cannot rename it. Again, a design team decision whether it is desirable to have some visual feedback as to the read/write permissions.
I am not getting a greyed out Copy in the Icon View context menu usually, but I have found a bug that causes this if you right click while in renaming. I'll fix this. Thanks.
Viko Adi Rahmawan (vikoadi) wrote : Posted in a previous version of this proposal | # |
Hello Jeremy,
this is a few regression a found during testing:
1. pressing enter key now open folder in a new tab,
2. and after that the notebook get the focus, so pressing left/right key will change tab.
3. F2 key doesn't rename, delete key doesn't delete file.
4. cannot undo file renaming
5. when i undo file deletion, it doesn't get focused
6. if i search for file and press enter, the file is selected but i cant navigate to other file by arrow key
7. Renaming file in miller column and List, even if its short name, reduce the font size
I will install this branch and see what more that i can get,
Viko
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Thanks for these Viko - a fresh pair of eyes can always find new things!
On 11 October 2014 10:40, Viko Adi Rahmawan <email address hidden> wrote:
> Hello Jeremy,
> this is a few regression a found during testing:
> 1. pressing enter key now open folder in a new tab,
> 2. and after that the notebook get the focus, so pressing left/right key
> will change tab.
> 3. F2 key doesn't rename, delete key doesn't delete file.
> 4. cannot undo file renaming
> 5. when i undo file deletion, it doesn't get focused
> 6. if i search for file and press enter, the file is selected but i cant
> navigate to other file by arrow key
> 7. Renaming file in miller column and List, even if its short name, reduce
> the font size
>
> I will install this branch and see what more that i can get,
> Viko
>
> --
>
> https:/
> You are the owner of lp:~jeremywootten/pantheon-files/all-views-vala.
>
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> Hello Jeremy,
> this is a few regression a found during testing:
> 1. pressing enter key now open folder in a new tab, --- FIXED
> 2. and after that the notebook get the focus, so pressing left/right key will
> change tab. --- FIXED
> 3. F2 key doesn't rename, delete key doesn't delete file. --- FIXED
> 4. cannot undo file renaming --- Trunk does not have this feature?
> 5. when i undo file deletion, it doesn't get focused --- Trunk does not have this feature?
> 6. if i search for file and press enter, the file is selected but i cant
> navigate to other file by arrow key --- FIXED
> 7. Renaming file in miller column and List, even if its short name, reduce the
> font size --- FIXED
>
> I will install this branch and see what more that i can get,
> Viko
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> Hello Jeremy,
> this is a few regression a found during testing:
> 1. pressing enter key now open folder in a new tab, --- FIXED
> 2. and after that the notebook get the focus, so pressing left/right key will
> change tab. --- FIXED
> 3. F2 key doesn't rename, delete key doesn't delete file. --- FIXED
> 4. cannot undo file renaming --- Trunk does not have this feature?
> 5. when i undo file deletion, it doesn't get focused --- Trunk does not have this feature?
> 6. if i search for file and press enter, the file is selected but i cant
> navigate to other file by arrow key --- FIXED
> 7. Renaming file in miller column and List, even if its short name, reduce the
> font size --- FIXED
>
> I will install this branch and see what more that i can get,
> Viko
Viko Adi Rahmawan (vikoadi) wrote : Posted in a previous version of this proposal | # |
just one more thing Jeremy,
1. in Icon View open a folder with rather large number of item, scroll to the bottom, start rubberbanding from last row to the last row-1, I get scrolled up to the top and dont want to scrolled down by placing mouse in the bottom
Other than that everything seems solid for me.
Thanks
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Thanks again Viko. The last revision fixes this.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
I don't really like that the icon spacing changes per-folder. I feel like this is a regression.
There's no longer any border around entries for renaming. I think this makes it unclear that you've actually entered renaming mode.
When there's a long label, renaming makes the text small. I'm not sure I like that. Either way, it's an unnecessary change from trunk. It should be proposed in its own branch.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
While renaming in column or list views,text should be centered vertically on the line instead of aligned to top.
Viko Adi Rahmawan (vikoadi) wrote : Posted in a previous version of this proposal | # |
Been using this all day and feels solid enough for me
great work Jeremy
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
Here's a relatively play-by-play look at me testing this for a bit today:
1. Icons in the icon view feel weirdly spaced out; I do like that they evenly space out, though. There just feels like there's a LOT of padding around each icon. Much lower information density.
2. Clicking things in the miller view just doesn't work... Oh, I have to click the icon. Clicking next to the text doesn't do anything and clicking right on it renames, which I guess is nice. I'd recommend only showing the rename if you click the text once it's already selected, otherwise it's a tiny target for browsing (which is a 1000x more important). Clicking the blank space anywhere on the line should open that folder. This is a regression.
3. There's a flash of "Loading..." every time I click a folder anywhere (even on the local SSD), which feels really, really glitchy. I'd consider it a regression.
4. Some things are italic and I don't know why. (Folders in /, things in the trash, maybe more.) I'd consider this a regression as well, or at least a weird design decision that isn't obvious.
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
As a note to number 4 from above, our interface font doesn't even have a true italic and I don't think we use italics anywhere else in the entire OS.
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
5. I feel like the list view should work similarly to how I described the miller view above: clicking anywhere on the line should to the "default" action, which in that case is opening the file or folder. The icon is too tiny of a target.
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
6. If I have a file highlighted in the icon view, then go to ctrl+click+drag to rubberband select another file, it looks like it starts rubberband selecting but then also starts dragging the highlighted file (even when not click+dragging near it).
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
7. Hitting F2 to rename doesn't work anymore.
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
After a while of having Files open, it will no longer open any files. Clicking an image does nothing, right-clicking and telling it to open in a different app does nothing. I'm not 100% sure this is the fault of this branch as I seem to recall this happening in the past.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
I have made the item width in icon view a fixed ratio of the icon size rather than automatic. The column and row spacings are also scaled to the icon size. I have set the ratios to give a more compact view.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
In order to distinguish more clearly, in icon view, the text of a selected item and a renaming item I have reimplemented the black border when renaming and also stopped displaying the text in the "selected" state when the item is selected so that there is a distinct state change when renaming (when the text becomes selected).
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Italic font for unwritable files reverted. Small font for editing long filenames reverted.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> 7. Hitting F2 to rename doesn't work anymore.
I cannot reproduce this - F2 functionality was restore in version 1596 of this branch.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> 7. Hitting F2 to rename doesn't work anymore.
I cannot reproduce this - F2 functionality was restore in version 1596 of this branch.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> After a while of having Files open, it will no longer open any files. Clicking
> an image does nothing, right-clicking and telling it to open in a different
> app does nothing. I'm not 100% sure this is the fault of this branch as I seem
> to recall this happening in the past.
Is this cleared by changing to another view and back? It sounds like the view has become stuck in the "updates_frozen" state somehow. There was a bug like this in an earlier version due to renaming not unfreezing the view in some circumstances but that was fixed.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> 6. If I have a file highlighted in the icon view, then go to ctrl+click+drag
> to rubberband select another file, it looks like it starts rubberband
> selecting but then also starts dragging the highlighted file (even when not
> click+dragging near it).
I cannot reproduce this in the later versions. Dragging with the primary button (left) should only occur when the cursor is in the hand shape (on the icon). However, dragging with the secondary button (right) occurs on both the icon and the text at the moment.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
> 5. I feel like the list view should work similarly to how I described the
> miller view above: clicking anywhere on the line should to the "default"
> action, which in that case is opening the file or folder. The icon is too tiny
> of a target.
An aim of this branch was to make the different views behave consistently - a lot more of the code is now shared. So clicking on an icon activates in all three views, clicking on the name text starts renaming in all three views, click on a blank area starts rubberbanding in all three view etc.
One of the bugs that this branch was intended to fix was the inability to access background functions in list and column views when the window was filled with files. This is why the rows do not activate everywhere. The blank part of a row in list and column views behaves pretty much like the background in icon view. Note also that in column view clicking on the far right of the row behaves like the extra columns in list view - i.e. clicking here deselects all selected files and does not select that row.
I accept that there may be a discoverability issue here and I am open to suggestions. The size of the target could be an issue at some zoom-levels. I already hide the selection helpers on small icons to ameliorate this. Another possibility would be to make the whole row activatable at small icon sizes but I feel that could be confusing.
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
Hey Jeremy, I get this when trying to make the latest revision:
make[2]: *** No rule to make target `../src/
make[1]: *** [src/CMakeFiles
make: *** [all] Error 2
Am I doing something wrong? :P
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
As usual, I forgot to add the new files to bzr - sorry. Now added.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Rev 1608 was necessary to get the vertical centering of the editable widget in list and column view. Prior to that I was using the same widget (a Gtk.TextView subclass) for both in the interest of simplicity and code economy, but I couldn't find an obvious way of having Gtk.TextView display vertically centred text. Now I use a different subclass of AbstractEditabl
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
Jeremy can you resolve conflicts with trunk? :)
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Conflicts with current trunk now resolved.
Danielle Foré (danrabbit) wrote : Posted in a previous version of this proposal | # |
Can we change the border on the editable label back to just 1px width?
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
The original C code used an 'illegal' fractional value for an int parameter, which I rounded up in Vala. I've now rounded it down and this has restored the 1px outline.
PerfectCarl (name-is-carl) wrote : Posted in a previous version of this proposal | # |
Here's the issues I found:
1) the empty trash is not always displayed.
Open the app, go to trash, close the app.
Re-open the app. The trash folder is opened by default but the top banner is missing
PerfectCarl (name-is-carl) wrote : Posted in a previous version of this proposal | # |
Here's the issues I found:
2) not a regression per se, but this still applies
https:/
3) when I search for a file (Ctrl+F) I once add in the console
[_LOG_
[_LOG_
I cannot reproduce it though.
Suggestion seeing the amount of work that went into this branch maybe a version bump (from 0.2) would be fair.
4) minor warnings that can be ironed out easily
/home/cran/
var context = widget.
/home/cran/
var state = widget.
5) suspicious warning
/home/cran/
if (increment != 0.0);
PerfectCarl (name-is-carl) wrote : Posted in a previous version of this proposal | # |
6) the files can't be opened with double click anymore. When double clicking a file, the file is getting renamed (if you clicked on the name) or do nothing if you clicked somewhere in the line.
When I single clicked the icon, the file is opened though.
But that's not convenient as the icon is very small: I am on the wrong end of Fitts law here
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
It was intentional that only clicking on the icon activates in all three views (in order to have consistent behaviour, shared code between the views and allow other desired behaviours when clicking on different parts of the filename column, especially in column view). But as several people have commented adversely, I will rethink this.
Viko Adi Rahmawan (vikoadi) wrote : Posted in a previous version of this proposal | # |
Hey Jeremy,
other regression i found:
- cannot type z in rename box
- cannot open menu using menu key
thanks
Cody Garver (codygarver) wrote : Posted in a previous version of this proposal | # |
Regression: can't drag files out of file-roller (opened archive) and onto empty space to extract them (in any view)
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
Vika, I can confirm the "Z" key issue. Very odd.
Cassidy James Blaede (cassidyjames) wrote : Posted in a previous version of this proposal | # |
Regression: back/forward buttons (like those on mice) don't work inside of the views, but they still do in other parts of the chrome (when the mouse cursor is over the sidebar or headerbar)
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
To avoid unnecessary difficulties in reviewing this branch I have made it respond like trunk to button presses in list and column views. i.e. clicking anywhere on the row will activate it (no single-click rename, blank part of row does not behave like background). However, rubberbanding works in column view unlike trunk.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
"Z" key issue solved. Silly error in implementing Ctrl-Z to undo while renaming.
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Dragging and dropping between applications (including FileRoller) now enabled.
Implemented/
1) Select on right click
2) Automagically switch to icon view for icon folders
3) Menu key activates context menu
4) Trash infobar shows in column view
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
Extra mouse button actions should now work. Fixed bug preventing display of some thumbnails
Jeremy Wootten (jeremywootten) wrote : Posted in a previous version of this proposal | # |
The latest revisions fix a number of bugs including some causing crashing under rapid random mouse clicking. Most debugging code has been removed and the format consistency of the code improved.
PerfectCarl (name-is-carl) wrote : | # |
Hey, nice work.
All the bugs I previously found are fixed now.
I found the the following
1) those critical warnings should be investigated:
[_LOG_LEVEL_FATAL 17:34:16.757606] gof_file_
[_LOG_LEVEL_FATAL 17:34:16.757701] Files will not function properly.
[_LOG_LEVEL_FATAL 17:34:16.758011] gof_file_
[_LOG_LEVEL_FATAL 17:34:16.758082] Files will not function properly.
[_LOG_LEVEL_FATAL 17:34:16.758735] gof_file_
[_LOG_LEVEL_FATAL 17:34:16.758800] Files will not function properly.
[_LOG_LEVEL_FATAL 17:34:16.759305] gof_file_
[_LOG_LEVEL_FATAL 17:34:16.759363] Files will not function properly.
[_LOG_LEVEL_FATAL 17:34:16.759540] gof_file_
[_LOG_LEVEL_FATAL 17:34:16.759596] Files will not function properly.
[_LOG_LEVEL_FATAL 17:34:16.762127] gof_file_
[_LOG_LEVEL_FATAL 17:34:16.762194] Files will not function properly.
[_LOG_LEVEL_FATAL 17:35:06.832406] gof_file_
[_LOG_LEVEL_FATAL 17:35:06.832465] Files will not function properly.
[_LOG_LEVEL_FATAL 17:35:06.832664] gof_file_
[_LOG_LEVEL_FATAL 17:35:06.832707] Files will not function properly.
2) minor code warnings: some async methods should be called as method_async.begin ()
/home/cran/
/home/cran/
/home/cran/
/home/cran/
/home/cran/
3) not sure it is related to this branch but, when trying to rename a file with an existing file name, I get this pretty ugly looking dialog.
http://
Jeremy Wootten (jeremywootten) wrote : | # |
Thanks Carl,
I put those extra assertions in and I thought I had tracked down the only
source of these warnings (its quiet on my machine) but I must have missed
something.
The warnings about async methods are in trunk so not related to this
branch,
I'll check out the dialog - thanks.
On 2 November 2014 16:47, PerfectCarl <email address hidden> wrote:
> Hey, nice work.
> All the bugs I previously found are fixed now.
>
> I found the the following
>
> 1) those critical warnings should be investigated:
>
> [_LOG_LEVEL_FATAL 17:34:16.757606] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:34:16.757701] Files will not function properly.
> [_LOG_LEVEL_FATAL 17:34:16.758011] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:34:16.758082] Files will not function properly.
> [_LOG_LEVEL_FATAL 17:34:16.758735] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:34:16.758800] Files will not function properly.
> [_LOG_LEVEL_FATAL 17:34:16.759305] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:34:16.759363] Files will not function properly.
> [_LOG_LEVEL_FATAL 17:34:16.759540] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:34:16.759596] Files will not function properly.
> [_LOG_LEVEL_FATAL 17:34:16.762127] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:34:16.762194] Files will not function properly.
> [_LOG_LEVEL_FATAL 17:35:06.832406] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:35:06.832465] Files will not function properly.
> [_LOG_LEVEL_FATAL 17:35:06.832664] gof_file_
> assertion 'size >= 1' failed
> [_LOG_LEVEL_FATAL 17:35:06.832707] Files will not function properly.
>
> 2) minor code warnings: some async methods should be called as
> method_async.begin ()
>
> /home/cran/
> warning: implicit .begin is deprecated
> /home/cran/
> warning: implicit .begin is deprecated
> /home/cran/
> warning: implicit .begin is deprecated
> /home/cran/
> warning: implicit .begin is deprecated
> /home/cran/
> warning: implicit .begin is deprecated
>
> 3) not sure it is related to this branch but, when trying to rename a file
> with an existing file name, I get this pretty ugly looking dialog.
> http://
>
>
> --
>
> https:/
> You are the owner of lp:~jeremywootten/pantheon-files/all-views-vala.
>
- 1649. By Jeremy Wootten
-
Fix rename error dialog and handling
PerfectCarl (name-is-carl) wrote : Posted in a previous version of this proposal | # |
When right clicking on a header I have the new file menu.
Shouldn't we have an option to add columns instead ?
PS : congrats, all the issue I reported are fixed in this version.
PS2: I did post a review message that got deleted it seems. Damn.
Jeremy Wootten (jeremywootten) wrote : | # |
The suggestion to have an option to add columns in list view is similar to Bug #1181547. Its a good idea - but will need another branch.
- 1650. By Jeremy Wootten
-
Reinstate interactive search in tree views; not implemented in Gtk.IconView
PerfectCarl (name-is-carl) wrote : Posted in a previous version of this proposal | # |
Okay, here goes the code review.
The QA will go in another comment (or I'll annotate the bug report directly).
So all in all, a good merge, congrats.
1) minor: remove the commented code
- in the cmakelist file
- in the code (mostly g_message )
- remove unused files from filesystem (see comments)
2) deal with the FIXME
- this is not a good thing to leave a FIXME without a bug report on lp.
note: the merge display is truncated by launchpad. I have to do it offline then.
PerfectCarl (name-is-carl) wrote : | # |
Damn, I commented the wrong merge proposal.
Please find my code comments there : https:/
PerfectCarl (name-is-carl) wrote : | # |
remove src/views/
I would suggest to add you to the AUTHORS file and about dialog as this merge is really non trivial and qualifies as being on the pantheon (ah ah) wall of fame !
Also because this merge is long, I had to take the review offline and annotate the code in a separate branch.
Nothing major though : spotted commented code and public event handlers.
You can make a diff from your branch and mine (https:/
Danielle Foré (danrabbit) wrote : | # |
Went through and verified that all the currently linked reports are indeed fixed by this branch :)
I did notice a couple of problems though:
1. In Icon view, right click and rename a folder (not the first one)
2. Move your cursor over the text box
3. See the the first folder in the view becomes highlighted
1. In Icon view, right click a folder and Open In > New Window
2. Close the new window
3. Right click the same folder
4. See that both "Open With" and "Open In" are now present.
- 1651. By Jeremy Wootten
-
Merged trunk
Jeremy Wootten (jeremywootten) wrote : | # |
Rev 1650 reverts the new "find on typing" function and re-instates the native interactive search in list and column view. Because Gtk.IconView does not have a native interactive search, a different solution will have to be found for this view, for example that implemented in lp:~jeremywootten/pantheon-files/all-views-vala-local-only-search, which uses the location bar find function to rapidly search just the current directory, providing a similar functionality to the native Gtk interactive search, except that at the moment, the found files are not selected (this could be implemented). If acceptable, it might be better to use the same function for all three views, for a consistent user experience.
- 1652. By Jeremy Wootten
-
Remove unnecessary comment lines, remove redundant files, remove or revise TODOs and FIXMEs, update about dialog authors list and AUTHORS file
- 1653. By Jeremy Wootten
-
Do not select current directory during actions on background
- 1654. By Jeremy Wootten
-
Allow 'Open with' menu action for background
- 1655. By Jeremy Wootten
-
Select focussed location
- 1656. By Jeremy Wootten
-
Eat motion events while renaming
Danielle Foré (danrabbit) wrote : | # |
When I go to paste something into the current view, it now reads "Paste into Folder". Can we revert this to just "Paste"? This is kind of disorienting. I'd only expect to see that string if I'd right clicked on a folder not the current view.
Danielle Foré (danrabbit) wrote : | # |
Can we get type-to-search back in Icon view? Slow completion is better than no completion :/
Danielle Foré (danrabbit) wrote : | # |
Oh sorry I didn't realize the search thing was fixed in another branch. Please disregard that comment.
- 1657. By Jeremy Wootten
-
Merge 'Open in' and 'Open with' submenus; Fix 'Open with other application' menuitem; improve app list filtering
- 1658. By Jeremy Wootten
-
Limit background clipboard actions to 'Paste'; only show paste action menuitem when pasting is possible
Danielle Foré (danrabbit) wrote : | # |
Small issue, but wouldn't consider it a merge blocker (it can be addressed after the merge if necessary). Similar to before with the open with:
Right click a folder
Open in new window
close new window
Right click same folder
Open in shows Terminal twice.
I think this branch is ready to be merged :) Great work Jeremy!
Cody Garver (codygarver) wrote : | # |
Forgive me if any of these are not relevant to this branch, here are my issues:
* Don't change the tab name to "Loading..." for local browsing, but would be nice to keep the spinner if possible; no big deal if it's not easy to implement
Icon View:
* Third line of long folder and filenames is cropped at the bottom, as is selection highlight
List View:
* No where to right click on to paste in a full directory
* Hand cursor appears when you hover over a file or folder icon, but not when you hover on the name (or its + or - icon)
Jeremy Wootten (jeremywootten) wrote : | # |
I can revert the change that changes the tab name to "loading" but keep the spinner.
The issue of long file names in icon view has come up before. I do not think it a problem that they are truncated when not renaming - that happens in all the views. The perceived problem is the truncation when renaming - which is a regression compared with trunk. This is because trunk uses a custom icon view that does not manage the editable widget, which then overlays as much of the view as needed to display the whole name. This branch uses a standard Gtk.IconView which handles the renaming and limits display of the editable widget to the available cell area (set to 3 lines at the moment). It is by no means trivial to change this. Perhaps a separate rename dialog could be shown? It is always possible to zoom in or switch to list view to edit a long name.
The ability to access the the background in List View with a full directory was implemented in an earlier revision of this branch but was reverted in order to reduce the number of changes introduced. Trunk has the same limitation. This can be re-introduced in a later branch.
The hand cursor is intended to indicate that dragging is possible. If you try and drag on the name you get rubberbanding instead. The code is quite flexible with regards to what actions occur and what cursor is shown when hovering or clicking on different regions of the row so if an agreed specification can be drawn up this can be implemented
Cody Garver (codygarver) wrote : | # |
The only issue I named that is definitely blocking the merge of this branch is the "Loading..." change, it was confirmed with Dan before posting my review.
The truncation is a problem but I suppose we should just make a report and deal with it some other time.
Accessing the background in a list view pre-dates this code, so ignore it.
We should hear from Dan about the hand cursor though.
Cody Garver (codygarver) wrote : | # |
Oh and theres a lot of commented out code that should be removed but you may already know this
- 1659. By Jeremy Wootten
-
Remove commented out code
- 1660. By Jeremy Wootten
-
Do not show 'Loading ...' on tab
Jeremy Wootten (jeremywootten) wrote : | # |
I think all the commented code that was added by this branch has now been removed.
I have stopped "Loading ..." being displayed on the tab during loading of the directory but the spinner still appears. A small visual flaw with this is that the name of the tab shifts to the right slightly when the spinner is hidden, since nothing takes the spinner's place and the available space is redistributed. One solution to this would be to display an icon for the directory (or a blank icon) in place of the spinner. DynamicNotebook already permits this.
- 1661. By Jeremy Wootten
-
Ensure gof_file_
icon_update_ internal is not called with invalid pix_size
Danielle Foré (danrabbit) wrote : | # |
If we showed a blank icon it would also make sure the labels are centered since they are already offset a bit by the tab close button. I'm +1 to that solution.
PerfectCarl (name-is-carl) wrote : Posted in a previous version of this proposal | # |
There is still commented code in that branch.
But to be fair this is a minor inconvenience and the codebase of pantheon-files is old enough that it could filed as a separate issue.
Besides, the work of everyone (maintainer and reviewer) will be simpler if that gigantic merge request is not stalled any longer.
PerfectCarl (name-is-carl) wrote : | # |
There is still commented code in that branch.
But to be fair this is a minor inconvenience and the codebase of pantheon-files is old enough that it could filed as a separate issue.
Besides, the work of everyone (maintainer and reviewer) will be simpler if that gigantic merge request is not stalled any longer.
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2011-08-06 10:29:32 +0000 |
3 | +++ .bzrignore 2014-11-22 15:05:49 +0000 |
4 | @@ -1,1 +1,1 @@ |
5 | -build |
6 | + |
7 | |
8 | === modified file 'AUTHORS' |
9 | --- AUTHORS 2011-07-02 12:29:59 +0000 |
10 | +++ AUTHORS 2014-11-22 15:05:49 +0000 |
11 | @@ -3,3 +3,5 @@ |
12 | Robert Roth |
13 | Vadim Rutkovsky |
14 | Rico Tzschichholz |
15 | +Mario Guerriero <mario@elementaryos.org> |
16 | +Jeremy Wootten <jeremy@elementaryos.org> |
17 | |
18 | === modified file 'CMakeLists.txt' |
19 | --- CMakeLists.txt 2014-10-05 06:30:05 +0000 |
20 | +++ CMakeLists.txt 2014-11-22 15:05:49 +0000 |
21 | @@ -22,7 +22,7 @@ |
22 | |
23 | find_package (Vala REQUIRED) |
24 | include (ValaVersion) |
25 | -ensure_vala_version ("0.26.0" MINIMUM) |
26 | +ensure_vala_version ("0.26" MINIMUM) |
27 | include (ValaPrecompile) |
28 | |
29 | IF (LIB_ONLY) |
30 | |
31 | === modified file 'data/schemas/org.pantheon.files.gschema.xml' |
32 | --- data/schemas/org.pantheon.files.gschema.xml 2014-10-18 17:39:19 +0000 |
33 | +++ data/schemas/org.pantheon.files.gschema.xml 2014-11-22 15:05:49 +0000 |
34 | @@ -127,7 +127,7 @@ |
35 | </key> |
36 | <key type="a(uss)" name="tab-info-list"> |
37 | <summary>Details of open tabs</summary> |
38 | - <default>[(0,"","")]</default> |
39 | + <default>[(0,'','')]</default> |
40 | <description>Array of tab info: View mode, root uri, tip uri (for Miller view)</description> |
41 | </key> |
42 | </schema> |
43 | @@ -176,4 +176,4 @@ |
44 | </key> |
45 | </schema> |
46 | |
47 | -</schemalist> |
48 | \ No newline at end of file |
49 | +</schemalist> |
50 | |
51 | === added file 'libcore/AbstractSlot.vala' |
52 | --- libcore/AbstractSlot.vala 1970-01-01 00:00:00 +0000 |
53 | +++ libcore/AbstractSlot.vala 2014-11-22 15:05:49 +0000 |
54 | @@ -0,0 +1,76 @@ |
55 | +/*** |
56 | + Copyright (C) 2014 elementary Developers and Jeremy Wootten |
57 | + |
58 | + This program is free software: you can redistribute it and/or modify it |
59 | + under the terms of the GNU Lesser General Public License version 3, as published |
60 | + by the Free Software Foundation. |
61 | + |
62 | + This program is distributed in the hope that it will be useful, but |
63 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
64 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
65 | + PURPOSE. See the GNU General Public License for more details. |
66 | + |
67 | + You should have received a copy of the GNU General Public License along |
68 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
69 | + |
70 | + Authors : Lucas Baudin <xapantu@gmail.com> |
71 | + Jeremy Wootten <jeremywootten@gmail.com> |
72 | +***/ |
73 | + |
74 | +namespace GOF { |
75 | + public abstract class AbstractSlot : GLib.Object { |
76 | + |
77 | + GOF.Directory.Async _directory; |
78 | + public GOF.Directory.Async? directory { |
79 | + get { |
80 | + AbstractSlot? current = get_current_slot (); |
81 | + if (current != null) |
82 | + return current._directory; |
83 | + else |
84 | + return null; |
85 | + } |
86 | + |
87 | + protected set {_directory = value;} |
88 | + } |
89 | + public GLib.File location { |
90 | + get {return directory.location;} |
91 | + } |
92 | + public string uri { |
93 | + get { return directory.file.uri;} |
94 | + } |
95 | + protected Gtk.Box extra_location_widgets; |
96 | + protected Gtk.Box content_box; |
97 | + protected int slot_number; |
98 | + protected int width; |
99 | + |
100 | + public void add_extra_widget (Gtk.Widget widget) { |
101 | + extra_location_widgets.pack_start (widget); |
102 | + } |
103 | + |
104 | + protected void init () { |
105 | + content_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); |
106 | + extra_location_widgets = new Gtk.Box (Gtk.Orientation.VERTICAL, 0); |
107 | + (content_box as Gtk.Box).pack_start (extra_location_widgets, false, false, 0); |
108 | + slot_number = -1; |
109 | + } |
110 | + |
111 | + public abstract unowned GLib.List<unowned GOF.File>? get_selected_files (); |
112 | + public abstract void set_active_state (bool set_active); |
113 | + public abstract unowned AbstractSlot? get_current_slot (); |
114 | + public abstract void reload (); |
115 | + public abstract void grab_focus (); |
116 | + public abstract void user_path_change_request (GLib.File loc, bool allow_mode_change = true); |
117 | + public abstract void select_first_for_empty_selection (); |
118 | + public abstract void select_glib_files (GLib.List<GLib.File> locations, GLib.File? focus_location); |
119 | + protected abstract void make_view (); |
120 | + public abstract void cancel (); |
121 | + |
122 | + public virtual void zoom_out () {} |
123 | + public virtual void zoom_in () {} |
124 | + public virtual void zoom_normal () {} |
125 | + public virtual bool set_all_selected (bool all_selected) {return false;} |
126 | + public virtual Gtk.Widget get_content_box () {return content_box as Gtk.Widget;} |
127 | + public virtual string? get_root_uri () {return directory.file.uri;} |
128 | + public virtual string? get_tip_uri () {return null;} |
129 | + } |
130 | +} |
131 | |
132 | === modified file 'libcore/CMakeLists.txt' |
133 | --- libcore/CMakeLists.txt 2014-08-05 22:40:12 +0000 |
134 | +++ libcore/CMakeLists.txt 2014-11-22 15:05:49 +0000 |
135 | @@ -15,6 +15,7 @@ |
136 | |
137 | vala_precompile(VALA_C ${PKGNAME} |
138 | AbstractSidebar.vala |
139 | + AbstractSlot.vala |
140 | gof-callwhenready.vala |
141 | gof-directory-async.vala |
142 | gof-preferences.vala |
143 | @@ -60,7 +61,7 @@ |
144 | marlin-progress-info.c |
145 | marlin-progress-info-manager.c |
146 | marlin-exec.c |
147 | - gof-abstract-slot.c |
148 | +# gof-abstract-slot.c |
149 | gof-file.c |
150 | marlin-icon-info.c |
151 | marlin-trash-monitor.c |
152 | @@ -80,7 +81,7 @@ |
153 | eel-string.h |
154 | eel-ui.h |
155 | eel-vfs-extensions.h |
156 | - gof-abstract-slot.h |
157 | +# gof-abstract-slot.h |
158 | gof-file.h |
159 | marlin-exec.h |
160 | marlin-file-conflict-dialog.h |
161 | |
162 | === modified file 'libcore/Plugin.vala' |
163 | --- libcore/Plugin.vala 2014-09-05 08:54:51 +0000 |
164 | +++ libcore/Plugin.vala 2014-11-22 15:05:49 +0000 |
165 | @@ -1,6 +1,6 @@ |
166 | public abstract class Marlin.Plugins.Base { |
167 | public virtual void directory_loaded (void* data) { } |
168 | - public virtual void context_menu (Gtk.Widget? widget, List<GOF.File> files) { } |
169 | + public virtual void context_menu (Gtk.Widget? widget, List<unowned GOF.File> files) { } |
170 | public virtual void ui (Gtk.UIManager? widget) { } |
171 | public virtual void update_sidebar (Gtk.Widget widget) { } |
172 | public virtual void update_file_info (GOF.File file) { } |
173 | |
174 | === modified file 'libcore/PluginManager.vala' |
175 | --- libcore/PluginManager.vala 2014-09-05 08:54:51 +0000 |
176 | +++ libcore/PluginManager.vala 2014-11-22 15:05:49 +0000 |
177 | @@ -169,7 +169,7 @@ |
178 | } |
179 | } |
180 | |
181 | - public void hook_context_menu (Gtk.Widget menu, List<GOF.File> files) { |
182 | + public void hook_context_menu (Gtk.Widget menu, List<unowned GOF.File> files) { |
183 | drop_menu_references (menu); |
184 | |
185 | if (menu is Gtk.Menu) |
186 | |
187 | === modified file 'libcore/eel-stock-dialogs.c' |
188 | --- libcore/eel-stock-dialogs.c 2013-09-09 03:08:16 +0000 |
189 | +++ libcore/eel-stock-dialogs.c 2014-11-22 15:05:49 +0000 |
190 | @@ -55,7 +55,6 @@ |
191 | GtkWindow *parent) |
192 | { |
193 | GtkWidget *dialog; |
194 | - |
195 | dialog = gtk_message_dialog_new (parent, 0, type, buttons_type, NULL); |
196 | g_object_set (dialog, "text", primary_text, "secondary-text", secondary_text, NULL); |
197 | |
198 | @@ -78,11 +77,9 @@ |
199 | GtkWindow *parent) |
200 | { |
201 | GtkDialog *dialog; |
202 | - |
203 | dialog = show_message_dialog (primary_text, secondary_text, type, |
204 | GTK_BUTTONS_OK, NULL, parent); |
205 | gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); |
206 | - |
207 | return dialog; |
208 | } |
209 | |
210 | |
211 | === modified file 'libcore/fm-list-model.c' |
212 | --- libcore/fm-list-model.c 2013-09-09 03:08:16 +0000 |
213 | +++ libcore/fm-list-model.c 2014-11-22 15:05:49 +0000 |
214 | @@ -37,6 +37,7 @@ |
215 | enum { |
216 | PROP_0, |
217 | PROP_HAS_CHILD, |
218 | + PROP_SIZE, |
219 | }; |
220 | |
221 | static GQuark attribute_name_q, |
222 | @@ -67,14 +68,11 @@ |
223 | |
224 | int stamp; |
225 | gboolean has_child; |
226 | - |
227 | - //GQuark sort_attribute; |
228 | gint sort_id; |
229 | + gint icon_size; |
230 | GtkSortType order; |
231 | |
232 | gboolean sort_directories_first; |
233 | - |
234 | - //GPtrArray *columns; |
235 | }; |
236 | |
237 | typedef struct FileEntry FileEntry; |
238 | @@ -98,7 +96,6 @@ |
239 | static void |
240 | file_entry_free (FileEntry *file_entry) |
241 | { |
242 | - //gof_file_unref (file_entry->file); |
243 | if (file_entry->reverse_map) { |
244 | g_hash_table_destroy (file_entry->reverse_map); |
245 | file_entry->reverse_map = NULL; |
246 | @@ -117,14 +114,12 @@ |
247 | static GtkTreeModelFlags |
248 | fm_list_model_get_flags (GtkTreeModel *tree_model) |
249 | { |
250 | - //return GTK_TREE_MODEL_ITERS_PERSIST; |
251 | return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST); |
252 | } |
253 | |
254 | static int |
255 | fm_list_model_get_n_columns (GtkTreeModel *tree_model) |
256 | { |
257 | - //return FM_LIST_MODEL_NUM_COLUMNS + FM_LIST_MODEL (tree_model)->details->columns->len; |
258 | return FM_LIST_MODEL_NUM_COLUMNS; |
259 | } |
260 | |
261 | @@ -134,6 +129,8 @@ |
262 | switch (index) { |
263 | case FM_LIST_MODEL_FILE_COLUMN: |
264 | return GOF_TYPE_FILE; |
265 | + case FM_LIST_MODEL_PIXBUF: |
266 | + return GDK_TYPE_PIXBUF; |
267 | default: |
268 | if (index < FM_LIST_MODEL_NUM_COLUMNS) { |
269 | return G_TYPE_STRING; |
270 | @@ -141,13 +138,6 @@ |
271 | return G_TYPE_INVALID; |
272 | } |
273 | } |
274 | - /*default: |
275 | - if (index < FM_LIST_MODEL_NUM_COLUMNS + FM_LIST_MODEL (tree_model)->details->columns->len) { |
276 | - return G_TYPE_STRING; |
277 | - } else { |
278 | - return G_TYPE_INVALID; |
279 | - } |
280 | - }*/ |
281 | } |
282 | |
283 | static void |
284 | @@ -157,6 +147,7 @@ |
285 | if (iter != NULL) { |
286 | iter->stamp = model->details->stamp; |
287 | iter->user_data = ptr; |
288 | + } else { |
289 | } |
290 | } |
291 | |
292 | @@ -204,7 +195,7 @@ |
293 | g_return_val_if_fail (iter->stamp == model->details->stamp, NULL); |
294 | |
295 | if (g_sequence_iter_is_end (iter->user_data)) { |
296 | - /* FIXME is this right? */ |
297 | + /* is this right? */ |
298 | return NULL; |
299 | } |
300 | |
301 | @@ -275,6 +266,15 @@ |
302 | g_value_set_string(value, file->formated_modified); |
303 | break; |
304 | |
305 | + case FM_LIST_MODEL_PIXBUF: |
306 | + g_value_init (value, GDK_TYPE_PIXBUF); |
307 | + if (file != NULL) { |
308 | + gof_file_update_icon (file, model->details->icon_size); |
309 | + if (file->pix != NULL) |
310 | + g_value_set_object(value, file->pix); |
311 | + } |
312 | + break; |
313 | + |
314 | } |
315 | } |
316 | |
317 | @@ -409,6 +409,8 @@ |
318 | FileEntry *file_entry; |
319 | GSequenceIter *ptr, *parent_ptr; |
320 | |
321 | + g_assert (file != NULL); |
322 | + |
323 | parent_ptr = NULL; |
324 | if (directory) { |
325 | parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map, |
326 | @@ -417,6 +419,7 @@ |
327 | |
328 | if (parent_ptr) { |
329 | file_entry = g_sequence_get (parent_ptr); |
330 | + g_assert (file_entry != NULL); |
331 | ptr = g_hash_table_lookup (file_entry->reverse_map, file); |
332 | } else { |
333 | ptr = g_hash_table_lookup (model->details->top_reverse_map, file); |
334 | @@ -588,7 +591,6 @@ |
335 | } |
336 | |
337 | /* Let the world know about our new order */ |
338 | - |
339 | g_assert (new_order != NULL); |
340 | |
341 | has_iter = FALSE; |
342 | @@ -672,10 +674,7 @@ |
343 | FileEntry *dummy_file_entry; |
344 | GtkTreeIter iter; |
345 | GtkTreePath *path; |
346 | - |
347 | dummy_file_entry = g_new0 (FileEntry, 1); |
348 | - //amtest |
349 | - //dummy_file_entry->file = parent_entry->file; |
350 | dummy_file_entry->parent = parent_entry; |
351 | dummy_file_entry->ptr = g_sequence_insert_sorted (parent_entry->files, dummy_file_entry, |
352 | fm_list_model_file_entry_compare_func, model); |
353 | @@ -696,7 +695,7 @@ |
354 | FileEntry *file_entry; |
355 | GSequenceIter *ptr, *parent_ptr; |
356 | GSequence *files; |
357 | - gboolean replace_dummy; |
358 | + gboolean replaced_dummy; |
359 | GHashTable *parent_hash; |
360 | |
361 | g_return_val_if_fail (file != NULL, FALSE); |
362 | @@ -711,25 +710,21 @@ |
363 | } |
364 | |
365 | if (ptr != NULL) { |
366 | - g_warning ("file already in tree (parent_ptr: %p)!!!\n", parent_ptr); |
367 | + g_debug ("file already in tree (parent_ptr: %p)!!!\n", parent_ptr); |
368 | return FALSE; |
369 | } |
370 | |
371 | file_entry = g_new0 (FileEntry, 1); |
372 | - file_entry->file = file; |
373 | + file_entry->file = file; /* Does not increase reference count */ |
374 | file_entry->parent = NULL; |
375 | file_entry->subdirectory = NULL; |
376 | file_entry->files = NULL; |
377 | |
378 | files = model->details->files; |
379 | parent_hash = model->details->top_reverse_map; |
380 | - |
381 | - //SPOTTED! |
382 | - //#if 0 |
383 | - replace_dummy = FALSE; |
384 | + replaced_dummy = FALSE; |
385 | |
386 | if (parent_ptr != NULL) { |
387 | - //log_printf (LOG_LEVEL_UNDEFINED, "parent_ptr != NULL %s\n", file->name); |
388 | file_entry->parent = g_sequence_get (parent_ptr); |
389 | /* At this point we set loaded. Either we saw |
390 | * "done" and ignored it waiting for this, or we do this |
391 | @@ -738,30 +733,25 @@ |
392 | file_entry->parent->loaded = 1; |
393 | parent_hash = file_entry->parent->reverse_map; |
394 | files = file_entry->parent->files; |
395 | - if (g_sequence_get_length (files) == 1) { |
396 | + if (g_sequence_get_length (files) == 1) { /* maybe the dummy row */ |
397 | GSequenceIter *dummy_ptr = g_sequence_get_iter_at_pos (files, 0); |
398 | FileEntry *dummy_entry = g_sequence_get (dummy_ptr); |
399 | - if (dummy_entry->file == NULL) { |
400 | - /* replace the dummy loading entry */ |
401 | - //model->details->stamp++; |
402 | + if (dummy_entry->file == NULL) { /* it is the dummy row - replace it */ |
403 | g_sequence_remove (dummy_ptr); |
404 | - |
405 | - replace_dummy = TRUE; |
406 | + replaced_dummy = TRUE; |
407 | } |
408 | } |
409 | } |
410 | - //#endif |
411 | file_entry->ptr = g_sequence_insert_sorted (files, file_entry, |
412 | fm_list_model_file_entry_compare_func, model); |
413 | |
414 | g_hash_table_insert (parent_hash, file, file_entry->ptr); |
415 | |
416 | - //#if 0 |
417 | iter.stamp = model->details->stamp; |
418 | iter.user_data = file_entry->ptr; |
419 | |
420 | path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); |
421 | - if (replace_dummy) { |
422 | + if (replaced_dummy) { |
423 | gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); |
424 | } else { |
425 | gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter); |
426 | @@ -769,18 +759,11 @@ |
427 | |
428 | if (gof_file_is_folder (file)) { |
429 | file_entry->files = g_sequence_new ((GDestroyNotify)file_entry_free); |
430 | - |
431 | add_dummy_row (model, file_entry); |
432 | - |
433 | gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), |
434 | path, &iter); |
435 | } |
436 | gtk_tree_path_free (path); |
437 | - |
438 | - //file_entry_free (file_entry); |
439 | - //g_object_unref(file); |
440 | - //#endif |
441 | - |
442 | return TRUE; |
443 | } |
444 | |
445 | @@ -916,11 +899,7 @@ |
446 | */ |
447 | add_dummy_row (model, parent_file_entry); |
448 | } |
449 | - /* FIXME we don't need to unref file here - clean up this part */ |
450 | - /*if (file_entry->file != NULL) { |
451 | - //log_printf (LOG_LEVEL_UNDEFINED, "remove file %s\n", file_entry->file->name); |
452 | - g_object_unref (file_entry->file); |
453 | - }*/ |
454 | + /* We don't need to unref file here - we did not add a ref */ |
455 | |
456 | if (file_entry->subdirectory != NULL) { |
457 | g_signal_emit (model, |
458 | @@ -937,15 +916,6 @@ |
459 | gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path); |
460 | |
461 | gtk_tree_path_free (path); |
462 | - |
463 | - if (parent_file_entry && g_sequence_get_length (parent_file_entry->files) == 0) { |
464 | - parent_iter.stamp = model->details->stamp; |
465 | - parent_iter.user_data = parent_file_entry->ptr; |
466 | - path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &parent_iter); |
467 | - gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), |
468 | - path, &parent_iter); |
469 | - gtk_tree_path_free (path); |
470 | - } |
471 | } |
472 | |
473 | void |
474 | @@ -1014,19 +984,21 @@ |
475 | return (file); |
476 | } |
477 | |
478 | -void fm_list_model_get_directory_file (FMListModel *model, GtkTreePath *path, GOFDirectoryAsync **directory, GOFFile **file) |
479 | +gboolean |
480 | +fm_list_model_get_directory_file (FMListModel *model, GtkTreePath *path, GOFDirectoryAsync **directory, GOFFile **file) |
481 | { |
482 | GtkTreeIter iter; |
483 | FileEntry *file_entry; |
484 | |
485 | *directory = NULL; |
486 | *file = NULL; |
487 | - if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) { |
488 | - return; |
489 | + if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) {; |
490 | + return FALSE; |
491 | } |
492 | file_entry = g_sequence_get (iter.user_data); |
493 | *directory = file_entry->subdirectory; |
494 | *file = file_entry->file; |
495 | + return TRUE; |
496 | } |
497 | |
498 | gboolean |
499 | @@ -1047,24 +1019,11 @@ |
500 | |
501 | file_entry->subdirectory = gof_directory_async_from_file (file_entry->file); |
502 | |
503 | - /* FIXME not sure the hash lookup is really needed gof_driectory_async_get_for_file is a always a new object */ |
504 | - if (g_hash_table_lookup (model->details->directory_reverse_map, |
505 | - file_entry->subdirectory) != NULL) { |
506 | - g_object_unref (file_entry->subdirectory); |
507 | - g_warning ("Already in directory_reverse_map, failing\n"); |
508 | - return FALSE; |
509 | - } |
510 | - |
511 | g_hash_table_insert (model->details->directory_reverse_map, |
512 | file_entry->subdirectory, file_entry->ptr); |
513 | file_entry->reverse_map = g_hash_table_new (g_direct_hash, g_direct_equal); |
514 | |
515 | - /* Return a ref too */ |
516 | - //gof_directory_ref (file_entry->subdirectory); |
517 | - *directory = file_entry->subdirectory; |
518 | - |
519 | - //load_dir_async (file_entry->subdirectory); |
520 | - |
521 | + *directory = file_entry->subdirectory; /* AbstractDirectoryView will maintain another reference on this */ |
522 | return TRUE; |
523 | } |
524 | |
525 | @@ -1087,8 +1046,6 @@ |
526 | file_entry->subdirectory); |
527 | file_entry->loaded = 0; |
528 | |
529 | - g_message ("remove all children\n"); |
530 | - //log_printf (LOG_LEVEL_UNDEFINED, "remove all children %d\n", g_sequence_get_length (file_entry->files)); |
531 | /* Remove all children */ |
532 | while (g_sequence_get_length (file_entry->files) > 0) { |
533 | child_ptr = g_sequence_get_begin_iter (file_entry->files); |
534 | @@ -1107,7 +1064,7 @@ |
535 | list_model_signals[SUBDIRECTORY_UNLOADED], 0, |
536 | file_entry->subdirectory); |
537 | |
538 | - g_object_unref (file_entry->subdirectory); |
539 | + g_object_unref (file_entry->subdirectory); /* AbstractDirectoryView will also release its reference */ |
540 | file_entry->subdirectory = NULL; |
541 | g_assert (g_hash_table_size (file_entry->reverse_map) == 0); |
542 | g_hash_table_destroy (file_entry->reverse_map); |
543 | @@ -1146,18 +1103,8 @@ |
544 | fm_list_model_dispose (GObject *object) |
545 | { |
546 | FMListModel *model; |
547 | - //int i; |
548 | - |
549 | model = FM_LIST_MODEL (object); |
550 | |
551 | - /*if (model->details->columns) { |
552 | - for (i = 0; i < model->details->columns->len; i++) { |
553 | - g_object_unref (model->details->columns->pdata[i]); |
554 | - } |
555 | - g_ptr_array_free (model->details->columns, TRUE); |
556 | - model->details->columns = NULL; |
557 | - }*/ |
558 | - |
559 | if (model->details->files) { |
560 | g_sequence_free (model->details->files); |
561 | model->details->files = NULL; |
562 | @@ -1196,7 +1143,6 @@ |
563 | model->details->stamp = g_random_int (); |
564 | model->details->sort_id = FM_LIST_MODEL_FILENAME; |
565 | model->details->order = GTK_SORT_ASCENDING; |
566 | - //model->details->columns = g_ptr_array_new (); |
567 | } |
568 | |
569 | static void |
570 | @@ -1222,6 +1168,13 @@ |
571 | FALSE, |
572 | G_PARAM_READWRITE)); |
573 | |
574 | + g_object_class_install_property (object_class, |
575 | + PROP_SIZE, |
576 | + g_param_spec_int ("size", "size", "icon size", |
577 | + 16, 128, |
578 | + 32, |
579 | + G_PARAM_READWRITE)); |
580 | + |
581 | |
582 | list_model_signals[SUBDIRECTORY_UNLOADED] = |
583 | g_signal_new ("subdirectory_unloaded", |
584 | @@ -1272,11 +1225,14 @@ |
585 | g_return_if_fail (FM_IS_LIST_MODEL (model)); |
586 | |
587 | model->details->has_child = has_child; |
588 | - /*if (model->details->has_child != has_child) |
589 | - { |
590 | - model->details->has_child = has_child; |
591 | - //g_object_notify (G_OBJECT (tree_view), "single-click"); |
592 | - }*/ |
593 | +} |
594 | + |
595 | +static void |
596 | +fm_list_model_set_icon_size (FMListModel *model, gint size) |
597 | +{ |
598 | + g_return_if_fail (FM_IS_LIST_MODEL (model)); |
599 | + |
600 | + model->details->icon_size = size; |
601 | } |
602 | |
603 | static void |
604 | @@ -1293,6 +1249,10 @@ |
605 | g_value_set_boolean (value, model->details->has_child); |
606 | break; |
607 | |
608 | + case PROP_SIZE: |
609 | + g_value_set_int (value, model->details->icon_size); |
610 | + break; |
611 | + |
612 | default: |
613 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
614 | break; |
615 | @@ -1313,57 +1273,16 @@ |
616 | fm_list_model_set_has_child (model, g_value_get_boolean (value)); |
617 | break; |
618 | |
619 | + case PROP_SIZE: |
620 | + fm_list_model_set_icon_size (model, g_value_get_int (value)); |
621 | + break; |
622 | + |
623 | default: |
624 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
625 | break; |
626 | } |
627 | } |
628 | |
629 | - |
630 | -#if 0 |
631 | -void |
632 | -fm_list_model_subdirectory_done_loading (FMListModel *model, NautilusDirectory *directory) |
633 | -{ |
634 | - GtkTreeIter iter; |
635 | - GtkTreePath *path; |
636 | - FileEntry *file_entry, *dummy_entry; |
637 | - GSequenceIter *parent_ptr, *dummy_ptr; |
638 | - GSequence *files; |
639 | - |
640 | - if (model == NULL || model->details->directory_reverse_map == NULL) { |
641 | - return; |
642 | - } |
643 | - parent_ptr = g_hash_table_lookup (model->details->directory_reverse_map, |
644 | - directory); |
645 | - if (parent_ptr == NULL) { |
646 | - return; |
647 | - } |
648 | - |
649 | - file_entry = g_sequence_get (parent_ptr); |
650 | - files = file_entry->files; |
651 | - |
652 | - /* Only swap loading -> empty if we saw no files yet at "done", |
653 | - * otherwise, toggle loading at first added file to the model. |
654 | - */ |
655 | - if (!nautilus_directory_is_not_empty (directory) && |
656 | - g_sequence_get_length (files) == 1) { |
657 | - dummy_ptr = g_sequence_get_iter_at_pos (file_entry->files, 0); |
658 | - dummy_entry = g_sequence_get (dummy_ptr); |
659 | - if (dummy_entry->file == NULL) { |
660 | - /* was the dummy file */ |
661 | - file_entry->loaded = 1; |
662 | - |
663 | - iter.stamp = model->details->stamp; |
664 | - iter.user_data = dummy_ptr; |
665 | - |
666 | - path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); |
667 | - gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); |
668 | - gtk_tree_path_free (path); |
669 | - } |
670 | - } |
671 | -} |
672 | -#endif |
673 | - |
674 | const gchar * |
675 | fm_list_model_get_string_from_column_id (gint id) |
676 | { |
677 | @@ -1376,6 +1295,8 @@ |
678 | return "type"; |
679 | case FM_LIST_MODEL_MODIFIED: |
680 | return "modified"; |
681 | + case FM_LIST_MODEL_PIXBUF: |
682 | + return "pixbuf"; |
683 | } |
684 | |
685 | g_return_val_if_reached ("name"); |
686 | @@ -1390,7 +1311,7 @@ |
687 | { "name", FM_LIST_MODEL_FILENAME }, |
688 | { "size", FM_LIST_MODEL_SIZE }, |
689 | { "type", FM_LIST_MODEL_TYPE }, |
690 | - { "modified", FM_LIST_MODEL_MODIFIED }, |
691 | + { "modified", FM_LIST_MODEL_MODIFIED}, |
692 | }; |
693 | |
694 | gint |
695 | |
696 | === modified file 'libcore/fm-list-model.h' |
697 | --- libcore/fm-list-model.h 2014-08-05 22:40:12 +0000 |
698 | +++ libcore/fm-list-model.h 2014-11-22 15:05:49 +0000 |
699 | @@ -28,6 +28,7 @@ |
700 | #include <gtk/gtk.h> |
701 | #include <gdk/gdk.h> |
702 | #include "gof-file.h" |
703 | +#include "../src/marlin-enum-types.h" |
704 | #include "pantheon-files-core.h" |
705 | |
706 | #ifndef FM_LIST_MODEL_H |
707 | @@ -48,6 +49,7 @@ |
708 | enum { |
709 | FM_LIST_MODEL_FILE_COLUMN, |
710 | FM_LIST_MODEL_COLOR, |
711 | + FM_LIST_MODEL_PIXBUF, |
712 | FM_LIST_MODEL_FILENAME, |
713 | FM_LIST_MODEL_SIZE, |
714 | FM_LIST_MODEL_TYPE, |
715 | @@ -88,19 +90,11 @@ |
716 | |
717 | GOFFile * fm_list_model_file_for_path (FMListModel *model, GtkTreePath *path); |
718 | GOFFile * fm_list_model_file_for_iter (FMListModel *model, GtkTreeIter *iter); |
719 | -void fm_list_model_get_directory_file (FMListModel *model, GtkTreePath *path, |
720 | +gboolean fm_list_model_get_directory_file (FMListModel *model, GtkTreePath *path, |
721 | GOFDirectoryAsync **directory, GOFFile **file); |
722 | gboolean fm_list_model_load_subdirectory (FMListModel *model, GtkTreePath *path, GOFDirectoryAsync **directory); |
723 | void fm_list_model_unload_subdirectory (FMListModel *model, GtkTreeIter *iter); |
724 | |
725 | -/*int fm_list_model_add_column (FMListModel *model, |
726 | - NautilusColumn *column);*/ |
727 | -/*int fm_list_model_get_column_number (FMListModel *model, |
728 | - const char *column_name);*/ |
729 | - |
730 | -/*void fm_list_model_subdirectory_done_loading (FMListModel *model, |
731 | - NautilusDirectory *directory);*/ |
732 | - |
733 | const gchar *fm_list_model_get_string_from_column_id (gint id); |
734 | gint fm_list_model_get_column_id_from_string (const gchar *colstr); |
735 | |
736 | |
737 | === removed file 'libcore/gof-abstract-slot.c' |
738 | --- libcore/gof-abstract-slot.c 2011-09-08 02:01:24 +0000 |
739 | +++ libcore/gof-abstract-slot.c 1970-01-01 00:00:00 +0000 |
740 | @@ -1,47 +0,0 @@ |
741 | -/* |
742 | - * Copyright (C) 2011, Lucas Baudin <xapantu@gmail.com> |
743 | - * |
744 | - * Marlin is free software; you can redistribute it and/or |
745 | - * modify it under the terms of the GNU General Public License as |
746 | - * published by the Free Software Foundation; either version 2 of the |
747 | - * License, or (at your option) any later version. |
748 | - * |
749 | - * Marlin is distributed in the hope that it will be useful, |
750 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
751 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
752 | - * General Public License for more details. |
753 | - * |
754 | - * You should have received a copy of the GNU General Public License |
755 | - * along with this program; if not, write to the Free Software |
756 | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
757 | - * |
758 | - */ |
759 | - |
760 | -/* |
761 | - * The AbstractSlot may be used by the plugins. They are needed because GOFWindowSlot |
762 | - * are in src (ok, they shouldn't, but it would require much work to move them, FIXME). |
763 | - **/ |
764 | - |
765 | -#include "gof-abstract-slot.h" |
766 | - |
767 | -G_DEFINE_ABSTRACT_TYPE (GOFAbstractSlot, gof_abstract_slot, G_TYPE_OBJECT) |
768 | - |
769 | - |
770 | -/** |
771 | - * Add a widget in the top part of the slot. |
772 | - **/ |
773 | -void gof_abstract_slot_add_extra_widget (GOFAbstractSlot* slot, GtkWidget* widget) |
774 | -{ |
775 | - gtk_box_pack_start(GTK_BOX (slot->extra_location_widgets), widget, FALSE, FALSE, 0); |
776 | - gtk_widget_show_all(slot->extra_location_widgets); |
777 | -} |
778 | - |
779 | -static void |
780 | -gof_abstract_slot_class_init (GOFAbstractSlotClass *klass) |
781 | -{ |
782 | -} |
783 | - |
784 | -static void |
785 | -gof_abstract_slot_init (GOFAbstractSlot *self) |
786 | -{ |
787 | -} |
788 | |
789 | === removed file 'libcore/gof-abstract-slot.h' |
790 | --- libcore/gof-abstract-slot.h 2011-09-08 02:01:24 +0000 |
791 | +++ libcore/gof-abstract-slot.h 1970-01-01 00:00:00 +0000 |
792 | @@ -1,56 +0,0 @@ |
793 | -/* |
794 | - * Copyright (C) 2011, Lucas Baudin <xapantu@gmail.com> |
795 | - * |
796 | - * Marlin is free software; you can redistribute it and/or |
797 | - * modify it under the terms of the GNU General Public License as |
798 | - * published by the Free Software Foundation; either version 2 of the |
799 | - * License, or (at your option) any later version. |
800 | - * |
801 | - * Marlin is distributed in the hope that it will be useful, |
802 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
803 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
804 | - * General Public License for more details. |
805 | - * |
806 | - * You should have received a copy of the GNU General Public License |
807 | - * along with this program; if not, write to the Free Software |
808 | - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
809 | - * |
810 | - */ |
811 | - |
812 | -#ifndef _GOF_ABSTRACT_SLOT_H |
813 | -#define _GOF_ABSTRACT_SLOT_H |
814 | - |
815 | -#include <gtk/gtk.h> |
816 | - |
817 | -G_BEGIN_DECLS |
818 | - |
819 | -#define GOF_TYPE_ABSTRACT_SLOT gof_abstract_slot_get_type() |
820 | -#define GOF_ABSTRACT_SLOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOF_TYPE_ABSTRACT_SLOT, GOFAbstractSlot)) |
821 | -#define GOF_ABSTRACT_SLOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GOF_TYPE_ABSTRACT_SLOT, GOFAbstractSlotClass)) |
822 | -#define GOF_IS_ABSTRACT_SLOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOF_TYPE_ABSTRACT_SLOT)) |
823 | -#define GOF_IS_ABSTRACT_SLOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOF_TYPE_ABSTRACT_SLOT)) |
824 | -#define GOF_ABSTRACT_SLOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GOF_TYPE_ABSTRACT_SLOT, GOFAbstractSlotClass)) |
825 | - |
826 | -typedef struct _GOFAbstractSlot GOFAbstractSlot; |
827 | -typedef struct _GOFAbstractSlotClass GOFAbstractSlotClass; |
828 | - |
829 | -struct _GOFAbstractSlot |
830 | -{ |
831 | - GObject parent; |
832 | - |
833 | - GtkWidget* extra_location_widgets; |
834 | -}; |
835 | - |
836 | -struct _GOFAbstractSlotClass |
837 | -{ |
838 | - GObjectClass parent_class; |
839 | -}; |
840 | - |
841 | -GType gof_abstract_slot_get_type (void) G_GNUC_CONST; |
842 | - |
843 | -GOFAbstractSlot *gof_abstract_slot_new (void); |
844 | -void gof_abstract_slot_add_extra_widget (GOFAbstractSlot* slot, GtkWidget* widget); |
845 | - |
846 | -G_END_DECLS |
847 | - |
848 | -#endif /* _GOF_ABSTRACT_SLOT_H */ |
849 | |
850 | === modified file 'libcore/gof-directory-async.vala' |
851 | --- libcore/gof-directory-async.vala 2014-10-29 15:02:53 +0000 |
852 | +++ libcore/gof-directory-async.vala 2014-11-22 15:05:49 +0000 |
853 | @@ -23,6 +23,7 @@ |
854 | public class GOF.Directory.Async : Object { |
855 | public GLib.File location; |
856 | public GOF.File file; |
857 | + public int icon_size = 32; |
858 | |
859 | /* we're looking for particular path keywords like *\/icons* .icons ... */ |
860 | public bool uri_contain_keypath_icons; |
861 | @@ -84,10 +85,9 @@ |
862 | |
863 | this.add_toggle_ref ((ToggleNotify) toggle_ref_notify); |
864 | this.unref (); |
865 | - debug ("dir %s ref_count %u", this.file.uri, this.ref_count); |
866 | |
867 | + debug ("created dir %s ref_count %u", this.file.uri, this.ref_count); |
868 | file_hash = new HashTable<GLib.File,GOF.File> (GLib.File.hash, GLib.File.equal); |
869 | - |
870 | uri_contain_keypath_icons = "/icons" in file.uri || "/.icons" in file.uri; |
871 | } |
872 | |
873 | @@ -101,6 +101,7 @@ |
874 | dir.remove_dir_from_cache (); |
875 | |
876 | dir.remove_toggle_ref ((ToggleNotify) toggle_ref_notify); |
877 | + } else { |
878 | } |
879 | } |
880 | |
881 | @@ -114,7 +115,7 @@ |
882 | } |
883 | } |
884 | |
885 | - private void clear_directory_info () { |
886 | + public void clear_directory_info () { |
887 | if (idle_consume_changes_id != 0) { |
888 | Source.remove ((uint) idle_consume_changes_id); |
889 | idle_consume_changes_id = 0; |
890 | @@ -156,11 +157,13 @@ |
891 | bool show_hidden = Preferences.get_default ().pref_show_hidden_files; |
892 | |
893 | foreach (GOF.File gof in file_hash.get_values ()) { |
894 | - if (gof.info != null && (!gof.is_hidden || show_hidden)) { |
895 | - if (track_longest_name) |
896 | - update_longest_file_name (gof); |
897 | + if (gof != null) { |
898 | + if (gof.info != null && (!gof.is_hidden || show_hidden)) { |
899 | + if (track_longest_name) |
900 | + update_longest_file_name (gof); |
901 | |
902 | - file_loaded (gof); |
903 | + file_loaded (gof); |
904 | + } |
905 | } |
906 | } |
907 | |
908 | @@ -187,8 +190,8 @@ |
909 | } |
910 | } |
911 | } |
912 | - |
913 | - done_loading (); |
914 | + if (!cancellable.is_cancelled ()) |
915 | + done_loading (); |
916 | } |
917 | |
918 | public void update_desktop_files () { |
919 | @@ -275,17 +278,21 @@ |
920 | file.is_mounted = false; |
921 | } |
922 | |
923 | - //TODO send err code |
924 | - done_loading (); |
925 | + if (!cancellable.is_cancelled ()) |
926 | + done_loading (); |
927 | } |
928 | |
929 | - public GOF.File? file_hash_lookup_location (GLib.File location) { |
930 | - GOF.File? result = file_hash.lookup (location); |
931 | - return result; |
932 | + public GOF.File? file_hash_lookup_location (GLib.File? location) { |
933 | + if (location != null && location is GLib.File) { |
934 | + GOF.File? result = file_hash.lookup (location); |
935 | + return result; |
936 | + } else { |
937 | + return null; |
938 | + } |
939 | } |
940 | |
941 | public void file_hash_add_file (GOF.File gof) { |
942 | - file_hash.insert (gof.location, gof); |
943 | + file_hash.insert (gof.location, gof); |
944 | } |
945 | |
946 | /* TODO move this to GOF.File */ |
947 | @@ -326,8 +333,9 @@ |
948 | |
949 | gof.update (); |
950 | |
951 | - if (gof.info != null && (!gof.is_hidden || Preferences.get_default ().pref_show_hidden_files)) |
952 | + if (gof.info != null && (!gof.is_hidden || Preferences.get_default ().pref_show_hidden_files)) { |
953 | file_added (gof); |
954 | + } |
955 | |
956 | if (!gof.is_hidden && gof.is_folder ()) { |
957 | /* add to sorted_dirs */ |
958 | @@ -523,7 +531,7 @@ |
959 | dir.file_hash.remove (gof.location); |
960 | } |
961 | |
962 | - public static Async? cache_lookup (GLib.File *file) { |
963 | + public static Async? cache_lookup (GLib.File? file) { |
964 | Async? cached_dir = null; |
965 | |
966 | if (directory_cache == null) { |
967 | @@ -532,6 +540,9 @@ |
968 | return null; |
969 | } |
970 | |
971 | + if (file == null) |
972 | + return null; |
973 | + |
974 | dir_cache_lock.@lock (); |
975 | cached_dir = directory_cache.lookup (file); |
976 | |
977 | @@ -575,6 +586,14 @@ |
978 | return file.directory; |
979 | } |
980 | |
981 | + public bool is_loading () { |
982 | + return this.state == State.LOADING; |
983 | + } |
984 | + |
985 | + public bool is_loaded () { |
986 | + return this.state == State.LOADED; |
987 | + } |
988 | + |
989 | public bool is_empty () { |
990 | uint file_hash_count = 0; |
991 | |
992 | @@ -605,7 +624,6 @@ |
993 | } |
994 | |
995 | /* Thumbnail loading */ |
996 | - public int icon_size; |
997 | private uint timeout_thumbsq = 0; |
998 | private bool thumbs_stop; |
999 | private bool thumbs_thread_running; |
1000 | @@ -619,7 +637,6 @@ |
1001 | this.unref (); |
1002 | return null; |
1003 | } |
1004 | - |
1005 | thumbs_thread_running = true; |
1006 | thumbs_stop = false; |
1007 | |
1008 | @@ -666,16 +683,21 @@ |
1009 | } |
1010 | |
1011 | public void queue_load_thumbnails (int size) { |
1012 | + icon_size = size; |
1013 | + if (this.state == State.LOADING) |
1014 | + return; |
1015 | + |
1016 | /* Do not interrupt loading thumbs at same size for this folder */ |
1017 | - if (icon_size == size && thumbs_thread_running) |
1018 | + if ((icon_size == size) && thumbs_thread_running) |
1019 | return; |
1020 | |
1021 | icon_size = size; |
1022 | thumbs_stop = true; |
1023 | |
1024 | /* Wait for thumbnail thread to stop then start a new thread */ |
1025 | - if (timeout_thumbsq == 0) { |
1026 | - timeout_thumbsq = Timeout.add (40, queue_thumbs_timeout_cb); |
1027 | - } |
1028 | + if (timeout_thumbsq != 0) |
1029 | + GLib.Source.remove (timeout_thumbsq); |
1030 | + |
1031 | + timeout_thumbsq = Timeout.add (40, queue_thumbs_timeout_cb); |
1032 | } |
1033 | } |
1034 | |
1035 | === modified file 'libcore/gof-file.c' |
1036 | --- libcore/gof-file.c 2014-10-16 16:26:45 +0000 |
1037 | +++ libcore/gof-file.c 2014-11-22 15:05:49 +0000 |
1038 | @@ -111,6 +111,7 @@ |
1039 | file->directory = g_object_ref (dir); |
1040 | else |
1041 | file->directory = NULL; |
1042 | + |
1043 | file->basename = g_file_get_basename (file->location); |
1044 | //file->parent_dir = g_file_enumerator_get_container (enumerator); |
1045 | |
1046 | @@ -137,7 +138,7 @@ |
1047 | void |
1048 | gof_file_icon_changed (GOFFile *file) |
1049 | { |
1050 | - GOFDirectoryAsync *dir; |
1051 | + GOFDirectoryAsync *dir = NULL; |
1052 | |
1053 | /* get the DirectoryAsync associated to the file */ |
1054 | dir = gof_directory_async_cache_lookup (file->directory); |
1055 | @@ -320,9 +321,10 @@ |
1056 | |
1057 | gof_file_update_formated_type (file); |
1058 | /* update icon */ |
1059 | - //g_message ("%s build new icon", G_STRFUNC); |
1060 | file->icon = g_content_type_get_icon (ftype); |
1061 | - gof_file_update_icon_internal (file, file->pix_size); |
1062 | + if (file->pix_size > 1) |
1063 | + gof_file_update_icon_internal (file, file->pix_size); |
1064 | + |
1065 | gof_file_icon_changed (file); |
1066 | } |
1067 | |
1068 | @@ -358,7 +360,6 @@ |
1069 | |
1070 | if (file->file_type == G_FILE_TYPE_SHORTCUT || file->file_type == G_FILE_TYPE_MOUNTABLE) { |
1071 | const char *target_uri = g_file_info_get_attribute_string (file->info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI); |
1072 | - /*g_message ("%s target uri: %s", G_STRFUNC, target_uri);*/ |
1073 | if (target_uri != NULL) { |
1074 | file->target_location = g_file_new_for_uri (target_uri); |
1075 | gof_file_target_location_update (file); |
1076 | @@ -471,7 +472,6 @@ |
1077 | file->icon = g_content_type_get_icon (ftype); |
1078 | } |
1079 | |
1080 | - |
1081 | file->utf8_collation_key = g_utf8_collate_key_for_filename (gof_file_get_display_name (file), -1); |
1082 | /* mark the thumb flags as state none, we'll load the thumbs once the directory |
1083 | * would be loaded on a thread */ |
1084 | @@ -504,7 +504,6 @@ |
1085 | if (g_file_info_has_attribute (file->info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT)) { |
1086 | file->can_unmount = g_file_info_get_attribute_boolean (file->info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT); |
1087 | } |
1088 | - |
1089 | gof_file_update_trash_info (file); |
1090 | gof_file_update_emblem (file); |
1091 | } |
1092 | @@ -512,6 +511,8 @@ |
1093 | static MarlinIconInfo * |
1094 | gof_file_get_special_icon (GOFFile *file, int size, GOFFileIconFlags flags) |
1095 | { |
1096 | + g_return_val_if_fail (size >= 1, NULL); |
1097 | + |
1098 | if (file->custom_icon_name != NULL) { |
1099 | if (g_path_is_absolute (file->custom_icon_name)) |
1100 | return marlin_icon_info_lookup_from_path (file->custom_icon_name, size); |
1101 | @@ -540,6 +541,7 @@ |
1102 | GIcon *gicon; |
1103 | |
1104 | g_return_val_if_fail (file, NULL); |
1105 | + g_return_val_if_fail (size >= 1, NULL); |
1106 | |
1107 | icon = gof_file_get_special_icon (file, size, flags); |
1108 | if (icon != NULL && !marlin_icon_info_is_fallback (icon)) |
1109 | @@ -574,6 +576,7 @@ |
1110 | { |
1111 | GdkPixbuf *pix; |
1112 | MarlinIconInfo *temp_nicon; |
1113 | + g_return_val_if_fail (size >= 1, NULL); |
1114 | |
1115 | pix = marlin_icon_info_get_pixbuf_force_size (nicon, size, force_size); |
1116 | if (pix == NULL) { |
1117 | @@ -592,7 +595,7 @@ |
1118 | { |
1119 | MarlinIconInfo *nicon; |
1120 | GdkPixbuf *pix; |
1121 | - |
1122 | + g_return_val_if_fail (size >= 1, NULL); |
1123 | nicon = gof_file_get_icon (file, size, flags); |
1124 | //nicon = gof_file_get_icon (file, size, 0); |
1125 | |
1126 | @@ -601,8 +604,6 @@ |
1127 | if (nicon) |
1128 | g_object_unref (nicon); |
1129 | //pix = gdk_pixbuf_new_from_file_at_size ("/usr/share/icons/hicolor/scalable/apps/marlin.svg", size, size, NULL); |
1130 | - /*if (pix && nicon) |
1131 | - g_message ("%s ref count %u %u", G_STRFUNC, G_OBJECT (nicon)->ref_count, G_OBJECT (pix)->ref_count);*/ |
1132 | |
1133 | return pix; |
1134 | } |
1135 | @@ -610,8 +611,7 @@ |
1136 | static void |
1137 | gof_file_update_icon_internal (GOFFile *file, gint size) |
1138 | { |
1139 | - /*g_message ("%s %s %d", G_STRFUNC, file->uri, file->flags);*/ |
1140 | - |
1141 | + g_return_if_fail (size >= 1); |
1142 | /* destroy pixbuff if already present */ |
1143 | _g_object_unref0 (file->pix); |
1144 | //g_clear_object (&file->pix); |
1145 | @@ -620,17 +620,17 @@ |
1146 | file->pix_size = size; |
1147 | } |
1148 | |
1149 | -/* This function is used by the icon renderer and only by it. |
1150 | +/* This function is used by the icon renderer and fm-list-model. |
1151 | * Store the pixbuf and update it only for size change. |
1152 | */ |
1153 | void gof_file_update_icon (GOFFile *file, gint size) |
1154 | { |
1155 | - if (size <=0) |
1156 | + if (size <= 1) |
1157 | return; |
1158 | + |
1159 | if (!(file->pix == NULL || file->pix_size != size)) |
1160 | return; |
1161 | |
1162 | - //g_message ("%s %s %d %d", G_STRFUNC, file->uri, file->flags, size); |
1163 | gof_file_update_icon_internal (file, size); |
1164 | } |
1165 | |
1166 | @@ -650,8 +650,10 @@ |
1167 | g_list_free (file->emblems_list); |
1168 | file->emblems_list = NULL; |
1169 | } |
1170 | + |
1171 | if(plugins != NULL) |
1172 | marlin_plugin_manager_update_file_info (plugins, file); |
1173 | + |
1174 | if(gof_file_is_symlink(file) || (file->is_desktop && file->target_gof)) |
1175 | { |
1176 | gof_file_add_emblem(file, "emblem-symbolic-link"); |
1177 | @@ -668,7 +670,6 @@ |
1178 | else |
1179 | gof_file_add_emblem (file, "emblem-unreadable"); |
1180 | } |
1181 | - |
1182 | /* TODO update signal on real change */ |
1183 | //g_warning ("update emblem %s", file.uri); |
1184 | if (file->emblems_list != NULL) |
1185 | @@ -750,7 +751,6 @@ |
1186 | } |
1187 | print_error (err); |
1188 | } |
1189 | - |
1190 | return info; |
1191 | } |
1192 | |
1193 | @@ -784,10 +784,15 @@ |
1194 | gchar *base_name; |
1195 | gchar *md5_hash; |
1196 | |
1197 | + /* Silently ignore invalid requests */ |
1198 | + if (file->pix_size <= 1) |
1199 | + return; |
1200 | + |
1201 | if (gof_file_get_thumbnail_path (file) == NULL) { |
1202 | /* get the thumbnail path from md5 filename */ |
1203 | md5_hash = g_compute_checksum_for_string (G_CHECKSUM_MD5, file->uri, -1); |
1204 | base_name = g_strdup_printf ("%s.png", md5_hash); |
1205 | + /* TODO Use $XDG_CACHE_HOME specified thumbnail directory instead of hard coding - when Tumbler does*/ |
1206 | file->thumbnail_path = g_build_filename (g_get_home_dir (), ".thumbnails", |
1207 | "normal", base_name, NULL); |
1208 | g_free (base_name); |
1209 | @@ -857,6 +862,8 @@ |
1210 | |
1211 | file->sort_column_id = FM_LIST_MODEL_FILENAME; |
1212 | file->sort_order = GTK_SORT_ASCENDING; |
1213 | + |
1214 | + file->is_expanded = FALSE; |
1215 | } |
1216 | |
1217 | static void gof_file_finalize (GObject* obj) { |
1218 | @@ -1332,11 +1339,14 @@ |
1219 | |
1220 | if (file->target_gof) |
1221 | return gof_file_is_executable (file->target_gof); |
1222 | - if (file->info == NULL) |
1223 | + if (file->info == NULL) { |
1224 | return FALSE; |
1225 | + } |
1226 | |
1227 | - if (gof_file_is_desktop_file (file)) |
1228 | + if (gof_file_is_desktop_file (file)) { |
1229 | return TRUE; |
1230 | + } |
1231 | + |
1232 | if (g_file_info_get_attribute_boolean (file->info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) |
1233 | { |
1234 | /* get the content type of the file */ |
1235 | @@ -1353,7 +1363,8 @@ |
1236 | * g_content_type_can_be_executable() for unix because it also returns |
1237 | * true for "text/plain" and we don't want that */ |
1238 | if (g_content_type_is_a (content_type, "application/x-executable") |
1239 | - || g_content_type_is_a (content_type, "application/x-shellscript")) |
1240 | + || g_content_type_is_a (content_type, "application/x-shellscript") |
1241 | + || g_content_type_is_a (content_type, "application/octet-stream")) |
1242 | { |
1243 | can_execute = TRUE; |
1244 | } |
1245 | @@ -1411,6 +1422,12 @@ |
1246 | return _g_object_ref0 (cached_file); |
1247 | } |
1248 | |
1249 | +void |
1250 | +gof_file_set_expanded (GOFFile *file, gboolean expanded) { |
1251 | + g_return_if_fail (file != NULL || !file->is_directory); |
1252 | + file->is_expanded = expanded; |
1253 | +} |
1254 | + |
1255 | GOFFile* |
1256 | gof_file_get (GFile *location) |
1257 | { |
1258 | @@ -1418,6 +1435,8 @@ |
1259 | GOFFile *file = NULL; |
1260 | GOFDirectoryAsync *dir = NULL; |
1261 | |
1262 | +g_return_val_if_fail (location != NULL && G_IS_FILE (location), NULL); |
1263 | + |
1264 | if ((parent = g_file_get_parent (location)) != NULL) { |
1265 | dir = gof_directory_async_cache_lookup (parent); |
1266 | if (dir != NULL) { |
1267 | @@ -1639,7 +1658,7 @@ |
1268 | //printf ("%s actions MOVE %d COPY %d suggested %d\n", G_STRFUNC, GDK_ACTION_MOVE, GDK_ACTION_COPY, suggested_action); |
1269 | } |
1270 | } |
1271 | - else if (gof_file_is_executable (file)) |
1272 | + else if (!gof_file_is_folder (file) && gof_file_is_executable (file)) |
1273 | { |
1274 | /* determine the possible actions */ |
1275 | actions = gdk_drag_context_get_actions (context) & (GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE); |
1276 | @@ -1689,7 +1708,6 @@ |
1277 | } |
1278 | |
1279 | if (error != NULL) { |
1280 | - g_message ("Could not start application on terminal: %s", error->message); |
1281 | g_error_free (error); |
1282 | } |
1283 | |
1284 | @@ -1881,7 +1899,7 @@ |
1285 | } |
1286 | |
1287 | gboolean |
1288 | -gof_files_launch_with (GList *files, GdkScreen *screen, GAppInfo* app_info) |
1289 | +gof_file_launch_files (GList *files, GdkScreen *screen, GAppInfo* app_info) |
1290 | { |
1291 | GdkAppLaunchContext *context; |
1292 | gboolean succeed; |
1293 | @@ -2087,11 +2105,14 @@ |
1294 | //marlin_file_changes_queue_file_added (new_file); |
1295 | if (error == NULL) |
1296 | gof_file_update_existing (op->file, new_file); |
1297 | - /*else |
1298 | - marlin_dialogs_show_error (NULL, error, "Failed to rename %s", op->file->name);*/ |
1299 | + else |
1300 | + marlin_dialogs_show_error (NULL, |
1301 | + error, |
1302 | + "Failed to rename %s", |
1303 | + g_file_get_parse_name (op->file->location)); |
1304 | |
1305 | //g_warning ("%s %u", G_STRFUNC, G_OBJECT (op->file)->ref_count); |
1306 | - gof_file_operation_complete (op, NULL, error); |
1307 | + gof_file_operation_complete (op, new_file, error); |
1308 | if (new_file != NULL) { |
1309 | g_object_unref (new_file); |
1310 | } else { |
1311 | @@ -2111,7 +2132,6 @@ |
1312 | //char *new_file_name; |
1313 | //gboolean success, name_changed; |
1314 | GError *error; |
1315 | - |
1316 | //g_warning ("%s %u", G_STRFUNC, G_OBJECT (file)->ref_count); |
1317 | g_return_if_fail (GOF_IS_FILE (file)); |
1318 | g_return_if_fail (new_name != NULL); |
1319 | |
1320 | === modified file 'libcore/gof-file.h' |
1321 | --- libcore/gof-file.h 2013-08-10 20:20:23 +0000 |
1322 | +++ libcore/gof-file.h 2014-11-22 15:05:49 +0000 |
1323 | @@ -84,6 +84,7 @@ |
1324 | gboolean is_directory; |
1325 | gboolean is_hidden; |
1326 | gboolean is_desktop; |
1327 | + gboolean is_expanded; |
1328 | GIcon *icon; |
1329 | gchar *custom_icon_name; |
1330 | GdkPixbuf *pix; |
1331 | @@ -200,6 +201,7 @@ |
1332 | gchar *gof_file_get_formated_time (GOFFile *file, const char *attr); |
1333 | gboolean gof_file_is_symlink (GOFFile *file); |
1334 | gboolean gof_file_is_desktop_file (GOFFile *file); |
1335 | +void gof_file_set_expanded (GOFFile *file, gboolean expanded); |
1336 | gchar *gof_file_list_to_string (GList *list, gsize *len); |
1337 | |
1338 | gboolean gof_file_same_filesystem (GOFFile *file_a, GOFFile *file_b); |
1339 | @@ -208,10 +210,9 @@ |
1340 | GdkDragContext *context, |
1341 | GdkDragAction *suggested_action_return); |
1342 | void gof_file_open_single (GOFFile *file, GdkScreen *screen, GAppInfo *app_info); |
1343 | -//gboolean gof_file_launch_with (GOFFile *file, GdkScreen *screen, GAppInfo* app_info); |
1344 | -gboolean gof_files_launch_with (GList *files, GdkScreen *screen, GAppInfo* app_info); |
1345 | +gboolean gof_file_launch_files (GList *files, GdkScreen *screen, GAppInfo* app_info); |
1346 | +gboolean gof_file_launch (GOFFile *file, GdkScreen *screen, GAppInfo *app_info); |
1347 | gboolean gof_file_execute (GOFFile *file, GdkScreen *screen, GList *file_list, GError **error); |
1348 | -gboolean gof_file_launch (GOFFile *file, GdkScreen *screen, GAppInfo *app_info); |
1349 | GAppInfo *gof_file_get_default_handler (GOFFile *file); |
1350 | |
1351 | void gof_file_icon_changed (GOFFile *file); |
1352 | |
1353 | === modified file 'libcore/marlin-file-changes-queue.c' |
1354 | --- libcore/marlin-file-changes-queue.c 2014-08-05 22:40:12 +0000 |
1355 | +++ libcore/marlin-file-changes-queue.c 2014-11-22 15:05:49 +0000 |
1356 | @@ -86,7 +86,6 @@ |
1357 | { |
1358 | MarlinFileChange *new_item; |
1359 | MarlinFileChangesQueue *queue; |
1360 | - |
1361 | queue = marlin_file_changes_queue_get(); |
1362 | |
1363 | new_item = g_new0 (MarlinFileChange, 1); |
1364 | @@ -146,7 +145,6 @@ |
1365 | MarlinFileChange *result; |
1366 | |
1367 | g_assert (queue != NULL); |
1368 | - |
1369 | /* dequeue the tail item while locking down the list */ |
1370 | g_mutex_lock (&queue->mutex); |
1371 | |
1372 | @@ -205,7 +203,6 @@ |
1373 | MarlinFileChangesQueue *queue; |
1374 | gboolean flush_needed; |
1375 | |
1376 | - |
1377 | additions = NULL; |
1378 | changes = NULL; |
1379 | deletions = NULL; |
1380 | |
1381 | === modified file 'libcore/marlin-file-operations.c' |
1382 | --- libcore/marlin-file-operations.c 2014-09-06 06:20:16 +0000 |
1383 | +++ libcore/marlin-file-operations.c 2014-11-22 15:05:49 +0000 |
1384 | @@ -2801,7 +2801,6 @@ |
1385 | int response; |
1386 | |
1387 | dirs = g_queue_new (); |
1388 | - |
1389 | retry: |
1390 | error = NULL; |
1391 | info = g_file_query_info (file, |
1392 | @@ -3605,7 +3604,6 @@ |
1393 | } |
1394 | return CREATE_DEST_DIR_FAILED; |
1395 | } |
1396 | - marlin_file_changes_queue_file_added (*dest); |
1397 | |
1398 | // Start UNDO-REDO |
1399 | marlin_undo_manager_data_add_origin_target_pair (job->undo_redo_data, src, *dest); |
1400 | @@ -4363,7 +4361,7 @@ |
1401 | if (copy_job->is_move) { |
1402 | marlin_file_changes_queue_file_moved (src, dest); |
1403 | } else { |
1404 | - marlin_file_changes_queue_file_added (dest); |
1405 | + marlin_file_changes_queue_file_added (dest); |
1406 | } |
1407 | |
1408 | /* If copying a trusted desktop file to the desktop, |
1409 | @@ -4573,8 +4571,8 @@ |
1410 | g_error_free (error); |
1411 | goto out; |
1412 | } |
1413 | - primary = f (_("Error while copying \"%B\"."), src); |
1414 | - secondary = f (_("There was an error copying the file into %F."), dest_dir); |
1415 | + primary = f (_("There was an Error while copying \"%s\"."), g_file_get_uri (src)); |
1416 | + secondary = f (_("There was an error copying the file into %s."), g_file_get_uri (dest_dir)); |
1417 | details = error->message; |
1418 | |
1419 | response = run_warning (job, |
1420 | @@ -5087,7 +5085,7 @@ |
1421 | if (job->skip_all_error) { |
1422 | goto out; |
1423 | } |
1424 | - primary = f (_("Error while moving \"%B\"."), src); |
1425 | + primary = f (_("Error while moving \"%F\"."), src); |
1426 | secondary = f (_("There was an error moving the file into %F."), dest_dir); |
1427 | details = error->message; |
1428 | |
1429 | @@ -5352,7 +5350,6 @@ |
1430 | job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); |
1431 | |
1432 | inhibit_power_manager ((CommonJob *)job, _("Moving Files")); |
1433 | - |
1434 | // Start UNDO-REDO |
1435 | if (!marlin_undo_manager_is_undo_redo (marlin_undo_manager_instance())) { |
1436 | if (g_file_has_uri_scheme (g_list_first(files)->data, "trash")) { |
1437 | @@ -5476,8 +5473,7 @@ |
1438 | if (debuting_files) { |
1439 | g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE)); |
1440 | } |
1441 | - |
1442 | - marlin_file_changes_queue_file_added (dest); |
1443 | + marlin_file_changes_queue_file_added (dest); |
1444 | /*if (position) { |
1445 | //marlin_file_changes_queue_schedule_position_set (dest, *position, common->screen_num); |
1446 | } else { |
1447 | @@ -6210,7 +6206,7 @@ |
1448 | |
1449 | if (res) { |
1450 | job->created_file = g_object_ref (dest); |
1451 | - marlin_file_changes_queue_file_added (dest); |
1452 | + marlin_file_changes_queue_file_added (dest); |
1453 | /*if (job->has_position) { |
1454 | //marlin_file_changes_queue_schedule_position_set (dest, job->position, common->screen_num); |
1455 | } else { |
1456 | |
1457 | === modified file 'libcore/marlin-icon-info.c' |
1458 | --- libcore/marlin-icon-info.c 2014-07-09 10:25:45 +0000 |
1459 | +++ libcore/marlin-icon-info.c 2014-11-22 15:05:49 +0000 |
1460 | @@ -378,7 +378,6 @@ |
1461 | GdkPixbuf *pixbuf; |
1462 | char *str_icon = g_icon_to_string (icon); |
1463 | |
1464 | - g_message ("%s stream %s\n", G_STRFUNC, str_icon); |
1465 | pixbuf = gdk_pixbuf_new_from_file (str_icon, NULL); |
1466 | |
1467 | if (pixbuf != NULL) { |
1468 | @@ -404,6 +403,8 @@ |
1469 | //GdkPixbuf *scaled_pixbuf = NULL; |
1470 | |
1471 | g_return_val_if_fail (icon && G_IS_ICON (icon), NULL); |
1472 | + size = MAX (1, size); |
1473 | + |
1474 | if (G_IS_LOADABLE_ICON (icon)) { |
1475 | LoadableIconKey lookup_key; |
1476 | LoadableIconKey *key; |
1477 | @@ -456,12 +457,14 @@ |
1478 | char *str_icon = g_icon_to_string (icon); |
1479 | gint width, height; |
1480 | |
1481 | - if (gdk_pixbuf_get_file_info (str_icon, &width, &height) != NULL) |
1482 | + gdk_pixbuf_get_file_info (str_icon, &width, &height); |
1483 | + if ((width >= 1 || width == -1) && (height >= 1 || height == -1)) |
1484 | pixbuf = gdk_pixbuf_new_from_file_at_size (str_icon, MIN (width, size), MIN (height, size), NULL); |
1485 | + |
1486 | /*icon_info = g_object_new (MARLIN_TYPE_ICON_INFO, NULL); |
1487 | icon_info->pixbuf = pixbuf;*/ |
1488 | - icon_info = marlin_icon_info_new_for_pixbuf (pixbuf); |
1489 | if (pixbuf != NULL) { |
1490 | + icon_info = marlin_icon_info_new_for_pixbuf (pixbuf); |
1491 | key = loadable_icon_key_new (icon, size); |
1492 | g_hash_table_insert (loadable_icon_cache, key, g_object_ref (icon_info)); |
1493 | g_free (str_icon); |
1494 | @@ -555,7 +558,7 @@ |
1495 | { |
1496 | GIcon *icon; |
1497 | MarlinIconInfo *info; |
1498 | - |
1499 | + g_return_val_if_fail (size >= 1, NULL); |
1500 | icon = g_themed_icon_new (name); |
1501 | info = marlin_icon_info_lookup (icon, size); |
1502 | g_object_unref (icon); |
1503 | @@ -570,6 +573,7 @@ |
1504 | GIcon *icon; |
1505 | MarlinIconInfo *info; |
1506 | |
1507 | + g_return_val_if_fail (size >= 1, NULL); |
1508 | icon_file = g_file_new_for_path (path); |
1509 | icon = g_file_icon_new (icon_file); |
1510 | info = marlin_icon_info_lookup (icon, size); |
1511 | @@ -745,4 +749,4 @@ |
1512 | g_object_unref (icon_file); |
1513 | g_object_unref (icon); |
1514 | loadable_icon_key_free (lookup_key); |
1515 | -} |
1516 | \ No newline at end of file |
1517 | +} |
1518 | |
1519 | === modified file 'libcore/pantheon-files-core-C.vapi' |
1520 | --- libcore/pantheon-files-core-C.vapi 2014-10-18 21:27:05 +0000 |
1521 | +++ libcore/pantheon-files-core-C.vapi 2014-11-22 15:05:49 +0000 |
1522 | @@ -14,20 +14,62 @@ |
1523 | { |
1524 | public class ListModel : GLib.Object, Gtk.TreeModel, Gtk.TreeDragDest, Gtk.TreeSortable |
1525 | { |
1526 | + [CCode (cprefix = "FM_LIST_MODEL_", cheader_filename = "fm-list-model.h")] |
1527 | + public enum ColumnID { |
1528 | + FILE_COLUMN, |
1529 | + COLOR, |
1530 | + PIXBUF, |
1531 | + FILENAME, |
1532 | + SIZE, |
1533 | + TYPE, |
1534 | + MODIFIED, |
1535 | + NUM_COLUMNS |
1536 | + } |
1537 | + |
1538 | public bool load_subdirectory(Gtk.TreePath path, out GOF.Directory.Async dir); |
1539 | + public bool unload_subdirectory(Gtk.TreeIter iter); |
1540 | public void add_file(GOF.File file, GOF.Directory.Async dir); |
1541 | - public GOF.File file_for_path(Gtk.TreePath path); |
1542 | + public void remove_file (GOF.File file, GOF.Directory.Async dir); |
1543 | + public void file_changed (GOF.File file, GOF.Directory.Async dir); |
1544 | + public unowned GOF.File file_for_path(Gtk.TreePath path); |
1545 | + public static GLib.Type get_type (); |
1546 | + public bool get_first_iter_for_file (GOF.File file, out Gtk.TreeIter iter); |
1547 | + public bool get_tree_iter_from_file (GOF.File file, GOF.Directory.Async directory, out Gtk.TreeIter iter); |
1548 | + public bool get_directory_file (Gtk.TreePath path, out unowned GOF.Directory.Async directory, out unowned GOF.File file); |
1549 | + public GOF.File file_for_iter (Gtk.TreeIter iter); |
1550 | + public void clear (); |
1551 | + public signal void subdirectory_unloaded (GOF.Directory.Async directory); |
1552 | } |
1553 | } |
1554 | |
1555 | -[CCode (cprefix = "MarlinFileOperations", lower_case_cprefix = "marlin_file_operations_", cheader_filename = "marlin-file-operations.h")] |
1556 | -namespace Marlin.FileOperations { |
1557 | - static bool has_trash_files (GLib.Mount mount); |
1558 | - static int prompt_empty_trash (Gtk.Window? parent_window); |
1559 | - static GLib.List<GLib.File> get_trash_dirs_for_mount (GLib.Mount mount); |
1560 | - static void empty_trash_dirs (Gtk.Window? parent_window, owned GLib.List<GLib.File> dirs); |
1561 | - static void empty_trash (Gtk.Widget? widget); |
1562 | - static void copy_move (GLib.List<GLib.File> files, void* relative_item_points, GLib.File target_dir, Gdk.DragAction copy_action, Gtk.Widget? parent_view = null, void* done_callback = null, void* done_callback_data = null); |
1563 | + |
1564 | +namespace Marlin { |
1565 | + [CCode (cprefix = "MarlinFileOperations", lower_case_cprefix = "marlin_file_operations_", cheader_filename = "marlin-file-operations.h")] |
1566 | + namespace FileOperations { |
1567 | + static void new_folder(Gtk.Widget? parent_view, Gdk.Point? target_point, GLib.File file, Marlin.CreateCallback? create_callback = null, void* data_callback = null); |
1568 | + static void new_folder_with_name(Gtk.Widget? parent_view, Gdk.Point? target_point, GLib.File file, string name, Marlin.CreateCallback? create_callback = null, void* data_callback = null); |
1569 | + static void new_folder_with_name_recursive(Gtk.Widget? parent_view, Gdk.Point? target_point, GLib.File file, string name, Marlin.CreateCallback? create_callback = null, void* data_callback = null); |
1570 | + static void mount_volume (Gtk.Window? parent_window, GLib.Volume volume, bool allow_autorun); |
1571 | + static void mount_volume_full (Gtk.Window? parent_window, GLib.Volume volume, bool allow_autorun, Marlin.MountCallback? mount_callback, GLib.Object? callback_data_object); |
1572 | + static void unmount_mount_full (Gtk.Window? parent_window, GLib.Mount mount, bool eject, bool check_trash, Marlin.UnmountCallback? unmount_callback, void* callback_data); |
1573 | + static void trash_or_delete (GLib.List<GLib.File> locations, Gtk.Window window, void* callback, void* callback_data); |
1574 | + static void @delete (GLib.List<GLib.File> locations, Gtk.Window window, void* callback, void* callback_data); |
1575 | + static bool has_trash_files (GLib.Mount mount); |
1576 | + static int prompt_empty_trash (Gtk.Window? parent_window); |
1577 | + static GLib.List<GLib.File> get_trash_dirs_for_mount (GLib.Mount mount); |
1578 | + static void empty_trash_dirs (Gtk.Window? parent_window, owned GLib.List<GLib.File> dirs); |
1579 | + static void empty_trash (Gtk.Widget? widget); |
1580 | + static void copy_move (GLib.List<GLib.File> files, void* relative_item_points, GLib.File target_dir, Gdk.DragAction copy_action, Gtk.Widget? parent_view = null, void* done_callback = null, void* done_callback_data = null); |
1581 | + static void new_file (Gtk.Widget parent_view, Gdk.Point? target_point, string parent_dir, string? target_filename, string? initial_contents, int length, Marlin.CreateCallback? create_callback = null, void* done_callback_data = null); |
1582 | + static void new_file_from_template (Gtk.Widget parent_view, Gdk.Point? target_point, GLib.File parent_dir, string? target_filename, GLib.File template, Marlin.CreateCallback? create_callback = null, void* done_callback_data = null); |
1583 | + } |
1584 | + [CCode (cheader_filename = "marlin-file-operations.h", has_target = false)] |
1585 | + public delegate void MountCallback (GLib.Volume volume, void* callback_data_object); |
1586 | + [CCode (cheader_filename = "marlin-file-operations.h", has_target = false)] |
1587 | + public delegate void UnmountCallback (void* callback_data); |
1588 | + [CCode (cheader_filename = "marlin-file-operations.h", has_target = false)] |
1589 | + public delegate void CreateCallback (GLib.File new_file, void* callback_data); |
1590 | + |
1591 | } |
1592 | |
1593 | [CCode (cprefix = "EelGtk", lower_case_cprefix = "eel_gtk_window_", cheader_filename = "eel-gtk-extensions.h")] |
1594 | @@ -36,6 +78,11 @@ |
1595 | public void set_initial_geometry_from_string (Gtk.Window win, string geometry, uint w, uint h, bool ignore_position, int left_offset, int top_offset); |
1596 | } |
1597 | |
1598 | +[CCode (cprefix = "EelGtk", lower_case_cprefix = "eel_gtk_widget_", cheader_filename = "eel-gtk-extensions.h")] |
1599 | +namespace EelGtk.Widget { |
1600 | + public Gdk.Screen get_screen (); |
1601 | +} |
1602 | + |
1603 | [CCode (cprefix = "EelGFile", lower_case_cprefix = "eel_g_file_", cheader_filename = "eel-gio-extensions.h")] |
1604 | namespace EelGFile { |
1605 | public static GLib.List<GLib.File> list_new_from_string (string filelist); |
1606 | @@ -46,6 +93,7 @@ |
1607 | public void pop_up_context_menu (Gtk.Menu menu, int16 offset_x, int16 offset_y, Gdk.EventButton event); |
1608 | public void gtk_widget_set_shown (Gtk.Widget widget, bool shown); |
1609 | public Gtk.MenuItem gtk_menu_append_separator (Gtk.Menu menu); |
1610 | + public unowned Gdk.Screen gtk_widget_get_screen (Gtk.Widget? widget); |
1611 | public const int16 DEFAULT_POPUP_MENU_DISPLACEMENT; |
1612 | } |
1613 | |
1614 | @@ -65,9 +113,16 @@ |
1615 | public string format_size (uint64 size); |
1616 | } |
1617 | |
1618 | +[CCode (cprefix = "Eel", lower_case_cprefix = "eel_", cheader_filename = "eel-string.h")] |
1619 | +namespace Eel { |
1620 | + public string? str_double_underscores (string? str); |
1621 | +} |
1622 | + |
1623 | [CCode (cprefix = "EelPango", lower_case_cprefix = "eel_pango_", cheader_filename = "eel-pango-extensions.h")] |
1624 | namespace EelPango { |
1625 | public unowned Pango.AttrList attr_list_small(); |
1626 | + public unowned Pango.AttrList attr_list_small_italic(); |
1627 | + public unowned Pango.AttrList attr_list_italic(); |
1628 | public unowned Pango.AttrList attr_list_big(); |
1629 | } |
1630 | |
1631 | @@ -82,6 +137,8 @@ |
1632 | public Gdk.Pixbuf get_pixbuf_nodefault(); |
1633 | public Gdk.Pixbuf get_pixbuf_at_size(int size); |
1634 | public static void clear_caches (); |
1635 | + public static void remove_cache (string path, int size); |
1636 | + public static void infos_caches (); |
1637 | } |
1638 | [CCode (cheader_filename = "marlin-trash-monitor.h")] |
1639 | public abstract class TrashMonitor : GLib.Object |
1640 | @@ -152,7 +209,7 @@ |
1641 | public void changes_consume_changes (bool consume_all); |
1642 | } |
1643 | |
1644 | -[CCode (cprefix = "GOF", lower_case_cprefix = "gof_")] |
1645 | +[CCode (cprefix = "GOF", lower_case_cprefix = "gof_", ref_function = "gof_file_ref", unref_function = "gof_file_unref")] |
1646 | namespace GOF { |
1647 | |
1648 | [CCode (cheader_filename = "gof-file.h")] |
1649 | @@ -171,9 +228,11 @@ |
1650 | public const string GIO_DEFAULT_ATTRIBUTES; |
1651 | |
1652 | public File(GLib.File location, GLib.File? dir); |
1653 | - public static GOF.File get(GLib.File location); |
1654 | + public static GOF.File @get(GLib.File location); |
1655 | public static GOF.File get_by_uri (string uri); |
1656 | public static File cache_lookup (GLib.File file); |
1657 | + public static bool launch_files (GLib.List<GOF.File> files, Gdk.Screen screen, GLib.AppInfo app); |
1658 | + public static void list_free (GLib.List<GOF.File> files); |
1659 | |
1660 | public void remove_from_caches (); |
1661 | public bool is_gone; |
1662 | @@ -192,14 +251,19 @@ |
1663 | public string tagstype; |
1664 | public Gdk.Pixbuf pix; |
1665 | public int pix_size; |
1666 | + public int sort_column_id; |
1667 | + public Gtk.SortType sort_order; |
1668 | |
1669 | public GLib.FileType file_type; |
1670 | public bool is_hidden; |
1671 | public bool is_directory; |
1672 | public bool is_desktop; |
1673 | + public void set_expanded (bool expanded); |
1674 | public bool is_folder(); |
1675 | public bool is_symlink(); |
1676 | public bool is_trashed(); |
1677 | + public bool is_writable (); |
1678 | + public bool is_executable (); |
1679 | public bool link_known_target; |
1680 | public uint flags; |
1681 | |
1682 | @@ -223,6 +287,7 @@ |
1683 | public bool has_permissions; |
1684 | public uint32 permissions; |
1685 | |
1686 | + public void open_single (Gdk.Screen screen, GLib.AppInfo app_info); |
1687 | public void update (); |
1688 | public void update_type (); |
1689 | public void update_icon (int size); |
1690 | @@ -250,18 +315,23 @@ |
1691 | public unowned string get_display_target_uri (); |
1692 | |
1693 | public GLib.AppInfo get_default_handler (); |
1694 | + |
1695 | + public static string list_to_string (GLib.List<GOF.File> list, out long len); |
1696 | + |
1697 | + public bool execute (Gdk.Screen screen, GLib.List<GLib.File>? files, out GLib.Error error); |
1698 | + public void rename (string new_name, GOF.FileOperationCallback callback); |
1699 | + |
1700 | + public GOF.File @ref (); |
1701 | + public GOF.File unref (); |
1702 | } |
1703 | |
1704 | + public delegate void FileOperationCallback (GOF.File file, GLib.File? result_location, GLib.Error? error, void* callback_data); |
1705 | + |
1706 | [CCode (cheader_filename = "gof-file.h")] |
1707 | public enum FileIconFlags |
1708 | { |
1709 | NONE, |
1710 | USE_THUMBNAILS |
1711 | } |
1712 | - |
1713 | - [CCode (cheader_filename = "gof-abstract-slot.h")] |
1714 | - public class AbstractSlot : GLib.Object { |
1715 | - public void add_extra_widget(Gtk.Widget widget); |
1716 | - } |
1717 | } |
1718 | |
1719 | |
1720 | === modified file 'libwidgets/Animations.vala' |
1721 | --- libwidgets/Animations.vala 2014-05-05 06:19:28 +0000 |
1722 | +++ libwidgets/Animations.vala 2014-11-22 15:05:49 +0000 |
1723 | @@ -1,6 +1,12 @@ |
1724 | namespace Marlin.Animation { |
1725 | |
1726 | + private static uint timeout_source_id = 0; |
1727 | public static void smooth_adjustment_to (Gtk.Adjustment adj, int final) { |
1728 | + if (timeout_source_id > 0) { |
1729 | + GLib.Source.remove (timeout_source_id); |
1730 | + timeout_source_id = 0; |
1731 | + } |
1732 | + |
1733 | var initial = adj.value; |
1734 | var to_do = final - initial; |
1735 | |
1736 | @@ -11,14 +17,17 @@ |
1737 | var newvalue = 0; |
1738 | var old_adj_value = adj.value; |
1739 | |
1740 | - Timeout.add (1000 / 60, () => { |
1741 | - /* If the user moves it at the same time, just stop the animation */ |
1742 | - if(old_adj_value != adj.value) |
1743 | + timeout_source_id = Timeout.add (1000 / 60, () => { |
1744 | + /* If the user move it at the same time, just stop the animation */ |
1745 | + if (old_adj_value != adj.value) { |
1746 | + timeout_source_id = 0; |
1747 | return false; |
1748 | + } |
1749 | |
1750 | if (newvalue >= to_do - 10) { |
1751 | /* to be sure that there is not a little problem */ |
1752 | adj.value = final; |
1753 | + timeout_source_id = 0; |
1754 | return false; |
1755 | } |
1756 | |
1757 | |
1758 | === modified file 'libwidgets/BreadcrumbsElements.vala' |
1759 | --- libwidgets/BreadcrumbsElements.vala 2014-05-24 03:48:19 +0000 |
1760 | +++ libwidgets/BreadcrumbsElements.vala 2014-11-22 15:05:49 +0000 |
1761 | @@ -188,4 +188,4 @@ |
1762 | |
1763 | return x; |
1764 | } |
1765 | -} |
1766 | \ No newline at end of file |
1767 | +} |
1768 | |
1769 | === modified file 'libwidgets/LocationBar.vala' |
1770 | --- libwidgets/LocationBar.vala 2014-07-30 02:20:58 +0000 |
1771 | +++ libwidgets/LocationBar.vala 2014-11-22 15:05:49 +0000 |
1772 | @@ -185,14 +185,13 @@ |
1773 | escape (); |
1774 | return true; |
1775 | } |
1776 | - |
1777 | return base.key_press_event (event); |
1778 | } |
1779 | |
1780 | public override bool button_press_event (Gdk.EventButton event) { |
1781 | if (is_focus) |
1782 | return base.button_press_event (event); |
1783 | - |
1784 | + |
1785 | foreach (BreadcrumbsElement element in elements) |
1786 | element.pressed = false; |
1787 | |
1788 | @@ -242,7 +241,7 @@ |
1789 | var el = get_element_from_coordinates ((int) event.x, (int) event.y); |
1790 | if (el != null) { |
1791 | selected = elements.index_of (el); |
1792 | - var newpath = get_path_from_element (el); |
1793 | + var newpath = sanitise_path (get_path_from_element (el)); |
1794 | path_changed (get_file_for_path (newpath)); |
1795 | } else |
1796 | grab_focus (); |
1797 | @@ -318,14 +317,18 @@ |
1798 | if (search_mode) |
1799 | set_entry_text (""); |
1800 | else |
1801 | - set_entry_text (GLib.Uri.unescape_string (get_elements_path () |
1802 | - .replace ("file:////", "/") |
1803 | - .replace ("file:///", "/") |
1804 | - .replace ("trash:///", "") |
1805 | - .replace ("network:///", ""))); |
1806 | + set_entry_text (sanitise_path (GLib.Uri.unescape_string (get_elements_path ()))); |
1807 | + |
1808 | |
1809 | return base.focus_in_event (event); |
1810 | } |
1811 | + |
1812 | + string sanitise_path (string path) { |
1813 | + return path.replace ("file:////", "/") |
1814 | + .replace ("file:///", "/") |
1815 | + .replace ("trash:///", "") |
1816 | + .replace ("network:///", ""); |
1817 | + } |
1818 | |
1819 | void on_grab_focus () { |
1820 | select_region (0, 0); |
1821 | @@ -398,7 +401,7 @@ |
1822 | icons.append (icon); |
1823 | } |
1824 | |
1825 | - public void complete () { |
1826 | + public void complete () { |
1827 | if (text_completion.length == 0) |
1828 | return; |
1829 | |
1830 | @@ -428,6 +431,7 @@ |
1831 | |
1832 | public void set_entry_cursor (Gdk.Cursor? cursor) { |
1833 | /* Only child 13 needs to be modified for the cursor - there may be a better way to do this */ |
1834 | + /* TODO - this doesn't work ? */ |
1835 | get_window ().get_children ().nth_data (13).set_cursor (cursor ?? new Gdk.Cursor (Gdk.CursorType.XTERM)); |
1836 | } |
1837 | |
1838 | @@ -439,7 +443,7 @@ |
1839 | secondary_icon_tooltip_text = tooltip; |
1840 | } |
1841 | } |
1842 | - |
1843 | + |
1844 | public double get_all_breadcrumbs_width (out int breadcrumbs_count) { |
1845 | double total_width = 0.0; |
1846 | breadcrumbs_count = 0; |
1847 | @@ -478,7 +482,6 @@ |
1848 | break; |
1849 | } |
1850 | } |
1851 | - |
1852 | return newpath; |
1853 | } |
1854 | |
1855 | @@ -493,7 +496,6 @@ |
1856 | if (element.display) |
1857 | strpath += element.text + "/"; |
1858 | } |
1859 | - |
1860 | return strpath; |
1861 | } |
1862 | |
1863 | @@ -530,7 +532,7 @@ |
1864 | * @param event a button event to compute the coords of the new menu. |
1865 | * |
1866 | **/ |
1867 | - private bool select_bread_from_coord (Gdk.EventButton event) { |
1868 | + private bool select_bread_from_coord (Gdk.EventButton event) { |
1869 | var el = get_element_from_coordinates ((int) event.x, (int) event.y); |
1870 | |
1871 | if (el != null) { |
1872 | |
1873 | === modified file 'plugins/network-places/plugin.vala' |
1874 | --- plugins/network-places/plugin.vala 2014-09-24 07:03:11 +0000 |
1875 | +++ plugins/network-places/plugin.vala 2014-11-22 15:05:49 +0000 |
1876 | @@ -29,17 +29,22 @@ |
1877 | } |
1878 | |
1879 | public class Files.Plugins.NetworkPlaces : Marlin.Plugins.Base { |
1880 | + private NetworkInfobar? infobar = null; |
1881 | + |
1882 | public override void directory_loaded (void* user_data) { |
1883 | var file = ((Object[]) user_data)[2] as GOF.File; |
1884 | - return_if_fail (file != null); |
1885 | |
1886 | if (file.is_network_uri_scheme ()) { |
1887 | - var slot = ((Object[]) user_data)[1] as GOF.AbstractSlot; |
1888 | - return_if_fail (slot != null); |
1889 | - |
1890 | - var infobar = new NetworkInfobar (); |
1891 | - slot.add_extra_widget (infobar); |
1892 | - infobar.show_all (); |
1893 | + if (infobar == null) { |
1894 | + var slot = ((Object[]) user_data)[1] as GOF.AbstractSlot; |
1895 | + return_if_fail (slot != null); |
1896 | + infobar = new NetworkInfobar (); |
1897 | + slot.add_extra_widget (infobar); |
1898 | + infobar.show_all (); |
1899 | + } |
1900 | + } else if (infobar != null) { |
1901 | + infobar.destroy (); |
1902 | + infobar = null; |
1903 | } |
1904 | } |
1905 | |
1906 | |
1907 | === modified file 'plugins/pantheon-files-ctags/plugin.vala' |
1908 | --- plugins/pantheon-files-ctags/plugin.vala 2014-08-05 20:46:06 +0000 |
1909 | +++ plugins/pantheon-files-ctags/plugin.vala 2014-11-22 15:05:49 +0000 |
1910 | @@ -17,7 +17,6 @@ |
1911 | |
1912 | [DBus (name = "org.elementary.pantheonfiles.db")] |
1913 | interface MarlinDaemon : Object { |
1914 | - //public abstract async HashTable<string,Variant> get_uri_infos_from_directory (string directory) throws IOError; |
1915 | public abstract async Variant get_uri_infos (string raw_uri) throws IOError; |
1916 | public abstract async bool record_uris (Variant[] entries, string directory) throws IOError; |
1917 | |
1918 | @@ -26,7 +25,6 @@ |
1919 | |
1920 | public class Marlin.Plugins.CTags : Marlin.Plugins.Base { |
1921 | private MarlinDaemon daemon; |
1922 | - //GOF.Directory.Async directory; |
1923 | GOF.File directory; |
1924 | private bool is_user_dir; |
1925 | private bool ignore_dir; |
1926 | @@ -50,41 +48,6 @@ |
1927 | } |
1928 | } |
1929 | |
1930 | - /*private void file_info_update (HashTable<string,Variant> rc, GOF.File file) |
1931 | - { |
1932 | - Variant row = rc.lookup (file.uri); |
1933 | - if (row == null) |
1934 | - return; |
1935 | - |
1936 | - VariantIter iter = row.iterator (); |
1937 | - warning ("iter n_children %d", (int) iter.n_children ()); |
1938 | - assert (iter.n_children () == 1); |
1939 | - VariantIter row_iter = iter.next_value ().iterator (); |
1940 | - warning ("row_iter n_children %d", (int) row_iter.n_children ()); |
1941 | - |
1942 | - if (row_iter.n_children () == 2) { |
1943 | - unowned string type = row_iter.next_value ().get_string (); |
1944 | - int n = int.parse (row_iter.next_value ().get_string ()); |
1945 | - file.tagstype = type; |
1946 | - //file.color = Preferences.tags_colors[n]; |
1947 | - file.update_type (); |
1948 | - message ("grrrrrr %s %d", type, n); |
1949 | - } |
1950 | - }*/ |
1951 | - |
1952 | - /*private async void files_infos_updates () |
1953 | - { |
1954 | - var rc = yield daemon.get_uri_infos_from_directory (directory.file.uri); |
1955 | - |
1956 | - foreach (var file in directory.unknown_types) { |
1957 | - message ("unknown %s %s", file.name, file.ftype); |
1958 | - file_info_update (rc, file); |
1959 | - } |
1960 | - directory.unknown_types = null; |
1961 | - |
1962 | - |
1963 | - }*/ |
1964 | - |
1965 | /* Arbitrary user dir list */ |
1966 | private const string users_dirs[2] = { |
1967 | "file:///home", |
1968 | @@ -112,7 +75,7 @@ |
1969 | } |
1970 | |
1971 | public override void directory_loaded (void* user_data) { |
1972 | - message ("CANCEL"); |
1973 | + debug ("CANCEL"); |
1974 | cancellable.cancel (); |
1975 | |
1976 | |
1977 | @@ -124,15 +87,12 @@ |
1978 | unknowns.clear (); |
1979 | cancellable.reset (); |
1980 | |
1981 | - //directory = GOF.Directory.Async.from_file(((Object[])user_data)[2] as GOF.File); |
1982 | directory = ((Object[]) user_data)[2] as GOF.File; |
1983 | - //warning ("CTags Plugin dir %s", directory.file.uri); |
1984 | - warning ("CTags Plugin dir %s", directory.uri); |
1985 | + debug ("CTags Plugin dir %s", directory.uri); |
1986 | is_user_dir = f_is_user_dir (directory.uri); |
1987 | ignore_dir = f_ignore_dir (directory.uri); |
1988 | } |
1989 | |
1990 | - //private Variant add_entry (string uri, string content_type, int modified_time) |
1991 | private Variant add_entry (GOF.File gof) { |
1992 | char* ptr_arr[4]; |
1993 | ptr_arr[0] = gof.uri; |
1994 | @@ -147,12 +107,11 @@ |
1995 | Variant[] entries = null; |
1996 | GOF.File gof; |
1997 | while ((gof = knowns.pop_head ()) != null) { |
1998 | - //warning ("--- known %s", gof.name); |
1999 | entries += add_entry (gof); |
2000 | } |
2001 | |
2002 | if (entries != null) { |
2003 | - warning ("--- known entries %d", entries.length); |
2004 | + debug ("--- known entries %d", entries.length); |
2005 | try { |
2006 | yield daemon.record_uris (entries, directory.uri); |
2007 | } catch (Error err) { |
2008 | @@ -165,7 +124,7 @@ |
2009 | GOF.File gof = null; |
2010 | |
2011 | var count = unknowns.get_length (); |
2012 | - message ("unknows queue nb: %u", count); |
2013 | + debug ("unknowns queue length: %u", count); |
2014 | if (count > 10) { |
2015 | /* query info the whole dir, we can clear the whole unknowns queue */ |
2016 | unknowns.clear (); |
2017 | @@ -188,11 +147,8 @@ |
2018 | } |
2019 | } else { |
2020 | while ((gof = unknowns.pop_head ()) != null) { |
2021 | - //warning ("--- unknown %s", gof.name); |
2022 | try { |
2023 | - //var info = gof.location.query_info (FileAttribute.STANDARD_CONTENT_TYPE, 0); |
2024 | var info = yield gof.location.query_info_async (FileAttribute.STANDARD_CONTENT_TYPE, 0, 0, cancellable); |
2025 | - warning ("--- unknown query_info %s", gof.info.get_name ()); |
2026 | add_to_knowns_queue (gof, info); |
2027 | } catch (Error err2) { |
2028 | warning ("query_info failed: %s %s", err2.message, gof.uri); |
2029 | @@ -200,7 +156,6 @@ |
2030 | |
2031 | } |
2032 | } |
2033 | - idle_consume_unknowns = 0; |
2034 | } |
2035 | |
2036 | private void add_to_knowns_queue (GOF.File file, FileInfo info) { |
2037 | @@ -214,6 +169,7 @@ |
2038 | } |
2039 | t_consume_knowns = Timeout.add (300, () => { |
2040 | consume_knowns_queue (); |
2041 | + t_consume_knowns = 0; |
2042 | return false; |
2043 | }); |
2044 | } |
2045 | @@ -225,25 +181,24 @@ |
2046 | if (idle_consume_unknowns == 0) |
2047 | idle_consume_unknowns = Idle.add (() => { |
2048 | consume_unknowns_queue (); |
2049 | + idle_consume_unknowns = 0; |
2050 | return false; |
2051 | }); |
2052 | } |
2053 | } |
2054 | |
2055 | private async void rreal_update_file_info (GOF.File file) { |
2056 | - //warning ("ctags update %s", file.name); |
2057 | try { |
2058 | var rc = yield daemon.get_uri_infos (file.uri); |
2059 | |
2060 | VariantIter iter = rc.iterator (); |
2061 | - //warning ("iter n_children %d", (int) iter.n_children ()); |
2062 | + debug ("iter n_children %d", (int) iter.n_children ()); |
2063 | assert (iter.n_children () == 1); |
2064 | VariantIter row_iter = iter.next_value ().iterator (); |
2065 | - //warning ("row_iter n_children %d", (int) row_iter.n_children ()); |
2066 | + debug ("row_iter n_children %d", (int) row_iter.n_children ()); |
2067 | |
2068 | if (row_iter.n_children () == 3) { |
2069 | uint64 modified = int64.parse (row_iter.next_value ().get_string ()); |
2070 | - //message ("%s %d %d", file.name, (int) file.info.get_attribute_uint64 (FileAttribute.TIME_MODIFIED), (int) modified); |
2071 | unowned string type = row_iter.next_value ().get_string (); |
2072 | file.color = int.parse (row_iter.next_value ().get_string ()); |
2073 | /* check modified time field only on user dirs. We don't want to query again and |
2074 | @@ -259,7 +214,6 @@ |
2075 | file.update_type (); |
2076 | } |
2077 | } |
2078 | - //message ("grrrrrr %s %s %d %s", myfile.name, type, n, myfile.ftype); |
2079 | } else { |
2080 | add_to_unknowns_queue (file); |
2081 | } |
2082 | @@ -277,9 +231,183 @@ |
2083 | /*if (file.ftype == "application/octet-stream")*/ |
2084 | rreal_update_file_info (file); |
2085 | } |
2086 | + |
2087 | + public override void context_menu (Gtk.Widget? widget, GLib.List<unowned GOF.File> selected_files) { |
2088 | + if (selected_files.length () < 1 || widget == null) |
2089 | + return; |
2090 | + |
2091 | + var menu = widget as Gtk.Menu; |
2092 | + var color_menu_item = new ColorWidget (); |
2093 | + color_menu_item.color_changed.connect ((ncolor) => { |
2094 | + set_color (selected_files, ncolor); |
2095 | + }); |
2096 | + |
2097 | + add_menuitem (menu, new Gtk.SeparatorMenuItem ()); |
2098 | + add_menuitem (menu, color_menu_item); |
2099 | + } |
2100 | + |
2101 | + private void add_menuitem (Gtk.Menu menu, Gtk.MenuItem menu_item) { |
2102 | + menu.append (menu_item); |
2103 | + menu_item.show (); |
2104 | + } |
2105 | + |
2106 | + private async void set_color (GLib.List<unowned GOF.File> files, int n) throws IOError { |
2107 | + Variant[] entries = null; |
2108 | + foreach (unowned GOF.File file in files) { |
2109 | + file.color = n; |
2110 | + entries += add_entry (file); |
2111 | + } |
2112 | + |
2113 | + if (entries != null) { |
2114 | + try { |
2115 | + yield daemon.record_uris (entries, ((GOF.File) files.data).uri); |
2116 | + } catch (Error err) { |
2117 | + warning ("%s", err.message); |
2118 | + } |
2119 | + } |
2120 | + } |
2121 | + |
2122 | + private class ColorWidget : Gtk.MenuItem { |
2123 | + private new bool has_focus; |
2124 | + private int height; |
2125 | + public signal void color_changed (int ncolor); |
2126 | + public ColorWidget () { |
2127 | + set_size_request (150, 20); |
2128 | + height = 20; |
2129 | + |
2130 | + button_press_event.connect (button_pressed_cb); |
2131 | + draw.connect (on_draw); |
2132 | + |
2133 | + select.connect (() => { |
2134 | + has_focus = true; |
2135 | + }); |
2136 | + |
2137 | + deselect.connect (() => { |
2138 | + has_focus = false; |
2139 | + }); |
2140 | + } |
2141 | + |
2142 | + private bool button_pressed_cb (Gdk.EventButton event) { |
2143 | + determine_button_pressed_event (event); |
2144 | + return true; |
2145 | + } |
2146 | + |
2147 | + private void determine_button_pressed_event (Gdk.EventButton event) { |
2148 | + int i; |
2149 | + int btnw = 10; |
2150 | + int btnh = 10; |
2151 | + int y0 = (height - btnh) /2; |
2152 | + int x0 = btnw+5; |
2153 | + int xpad = 9; |
2154 | + |
2155 | + if (event.y >= y0 && event.y <= y0+btnh) |
2156 | + for (i=1; i<=10; i++) { |
2157 | + if (event.x>= xpad+x0*i && event.x <= xpad+x0*i+btnw) { |
2158 | + color_changed (i-1); |
2159 | + break; |
2160 | + } |
2161 | + } |
2162 | + } |
2163 | + |
2164 | + protected bool on_draw (Cairo.Context cr) { |
2165 | + int i; |
2166 | + int btnw = 10; |
2167 | + int btnh = 10; |
2168 | + int y0 = (height - btnh) /2; |
2169 | + int x0 = btnw+5; |
2170 | + int xpad = 9; |
2171 | + |
2172 | + for (i=1; i<=10; i++) { |
2173 | + if (i==1) |
2174 | + DrawCross (cr,xpad + x0*i, y0+1, btnw-2, btnh-2); |
2175 | + else { |
2176 | + DrawRoundedRectangle (cr,xpad + x0*i, y0, btnw, btnh, "stroke", i-1); |
2177 | + DrawRoundedRectangle (cr,xpad + x0*i, y0, btnw, btnh, "fill", i-1); |
2178 | + DrawGradientOverlay (cr,xpad + x0*i, y0, btnw, btnh); |
2179 | + } |
2180 | + } |
2181 | + |
2182 | + return true; |
2183 | + } |
2184 | + |
2185 | + private void DrawCross (Cairo.Context cr, int x, int y, int w, int h) { |
2186 | + cr.new_path (); |
2187 | + cr.set_line_width (2.0); |
2188 | + cr.move_to (x, y); |
2189 | + cr.rel_line_to (w, h); |
2190 | + cr.move_to (x, y+h); |
2191 | + cr.rel_line_to (w, -h); |
2192 | + cr.set_source_rgba (0,0,0,0.6); |
2193 | + cr.stroke(); |
2194 | + |
2195 | + cr.close_path (); |
2196 | + } |
2197 | + |
2198 | + /* |
2199 | + * Create a rounded rectangle using the Bezier curve. |
2200 | + * Adapted from http://cairographics.org/cookbook/roundedrectangles/ |
2201 | + */ |
2202 | + private void DrawRoundedRectangle (Cairo.Context cr, int x, int y, int w, int h, string style, int color) { |
2203 | + int radius_x=2; |
2204 | + int radius_y=2; |
2205 | + double ARC_TO_BEZIER = 0.55228475; |
2206 | + |
2207 | + if (radius_x > w - radius_x) |
2208 | + radius_x = w / 2; |
2209 | + |
2210 | + if (radius_y > h - radius_y) |
2211 | + radius_y = h / 2; |
2212 | + |
2213 | + /* approximate (quite close) the arc using a bezier curve */ |
2214 | + double ca = ARC_TO_BEZIER * radius_x; |
2215 | + double cb = ARC_TO_BEZIER * radius_y; |
2216 | + |
2217 | + cr.new_path (); |
2218 | + cr.set_line_width (0.7); |
2219 | + cr.set_tolerance (0.1); |
2220 | + cr.move_to (x + radius_x, y); |
2221 | + cr.rel_line_to (w - 2 * radius_x, 0.0); |
2222 | + cr.rel_curve_to (ca, 0.0, radius_x, cb, radius_x, radius_y); |
2223 | + cr.rel_line_to (0, h - 2 * radius_y); |
2224 | + cr.rel_curve_to (0.0, cb, ca - radius_x, radius_y, -radius_x, radius_y); |
2225 | + cr.rel_line_to (-w + 2 * radius_x, 0); |
2226 | + cr.rel_curve_to (-ca, 0, -radius_x, -cb, -radius_x, -radius_y); |
2227 | + cr.rel_line_to (0, -h + 2 * radius_y); |
2228 | + cr.rel_curve_to (0.0, -cb, radius_x - ca, -radius_y, radius_x, -radius_y); |
2229 | + |
2230 | + switch (style) { |
2231 | + default: |
2232 | + case "fill": |
2233 | + Gdk.RGBA rgba = Gdk.RGBA (); |
2234 | + rgba.parse (GOF.Preferences.TAGS_COLORS[color]); |
2235 | + Gdk.cairo_set_source_rgba (cr, rgba); |
2236 | + cr.fill (); |
2237 | + break; |
2238 | + case "stroke": |
2239 | + cr.set_source_rgba (0,0,0,0.5); |
2240 | + cr.stroke (); |
2241 | + break; |
2242 | + } |
2243 | + |
2244 | + cr.close_path (); |
2245 | + } |
2246 | + |
2247 | + /* |
2248 | + * Draw the overlaying gradient |
2249 | + */ |
2250 | + private void DrawGradientOverlay (Cairo.Context cr, int x, int y, int w, int h) { |
2251 | + var radial = new Cairo.Pattern.radial (w, h, 1, 0.0, 0.0, 0.0); |
2252 | + radial.add_color_stop_rgba (0, 0.3, 0.3, 0.3,0.0); |
2253 | + radial.add_color_stop_rgba (1, 0.0, 0.0, 0.0,0.5); |
2254 | + |
2255 | + cr.set_source (radial); |
2256 | + cr.rectangle (x,y,w,h); |
2257 | + cr.fill (); |
2258 | + } |
2259 | + } |
2260 | } |
2261 | |
2262 | - |
2263 | public Marlin.Plugins.Base module_init () { |
2264 | return new Marlin.Plugins.CTags (); |
2265 | } |
2266 | + |
2267 | |
2268 | === modified file 'plugins/pantheon-files-trash/plugin.vala' |
2269 | --- plugins/pantheon-files-trash/plugin.vala 2014-01-07 22:25:32 +0000 |
2270 | +++ plugins/pantheon-files-trash/plugin.vala 2014-11-22 15:05:49 +0000 |
2271 | @@ -30,22 +30,26 @@ |
2272 | |
2273 | public override void directory_loaded (void* user_data) { |
2274 | GOF.File file = ((Object[]) user_data)[2] as GOF.File; |
2275 | + /* Ignore directories other than trash and ignore reloading trash */ |
2276 | if (file.location.get_uri_scheme () == "trash") { |
2277 | - assert (((Object[]) user_data)[1] is GOF.AbstractSlot); |
2278 | - GOF.AbstractSlot slot = ((Object[]) user_data)[1] as GOF.AbstractSlot; |
2279 | - |
2280 | - infobar = new Gtk.InfoBar (); |
2281 | - (infobar.get_content_area () as Gtk.Box).add (new Gtk.Label (_("These items may be deleted by emptying the trash."))); |
2282 | - infobar.add_button (_("Empty the Trash"), 0); |
2283 | - infobar.response.connect ((self, response) => { |
2284 | - Marlin.FileOperations.empty_trash (self); |
2285 | - }); |
2286 | - infobar.set_message_type (Gtk.MessageType.INFO); |
2287 | - |
2288 | - infobar.set_response_sensitive (0, !TrashMonitor.is_empty ()); |
2289 | - |
2290 | - slot.add_extra_widget (infobar); |
2291 | - infobar.show_all (); |
2292 | + /* Only add infobar once */ |
2293 | + if (infobar == null || infobar.get_parent () == null) { |
2294 | + assert (((Object[]) user_data)[1] is GOF.AbstractSlot); |
2295 | + GOF.AbstractSlot slot = ((Object[]) user_data)[1] as GOF.AbstractSlot; |
2296 | + infobar = new Gtk.InfoBar (); |
2297 | + (infobar.get_content_area () as Gtk.Box).add (new Gtk.Label (_("These items may be deleted by emptying the trash."))); |
2298 | + infobar.add_button (_("Empty the Trash"), 0); |
2299 | + infobar.response.connect ((self, response) => { |
2300 | + Marlin.FileOperations.empty_trash (self); |
2301 | + }); |
2302 | + infobar.set_message_type (Gtk.MessageType.INFO); |
2303 | + infobar.set_response_sensitive (0, !TrashMonitor.is_empty ()); |
2304 | + slot.add_extra_widget (infobar); |
2305 | + infobar.show_all (); |
2306 | + } |
2307 | + } else if (infobar != null) { |
2308 | + infobar.destroy (); |
2309 | + infobar = null; |
2310 | } |
2311 | } |
2312 | } |
2313 | |
2314 | === added file 'src/AbstractEditableLabel.vala' |
2315 | --- src/AbstractEditableLabel.vala 1970-01-01 00:00:00 +0000 |
2316 | +++ src/AbstractEditableLabel.vala 2014-11-22 15:05:49 +0000 |
2317 | @@ -0,0 +1,96 @@ |
2318 | +/* |
2319 | + Copyright (C) 2014 elementary Developers |
2320 | + |
2321 | + This program is free software: you can redistribute it and/or modify it |
2322 | + under the terms of the GNU Lesser General Public License version 3, as published |
2323 | + by the Free Software Foundation. |
2324 | + |
2325 | + This program is distributed in the hope that it will be useful, but |
2326 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
2327 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2328 | + PURPOSE. See the GNU General Public License for more details. |
2329 | + |
2330 | + You should have received a copy of the GNU General Public License along |
2331 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
2332 | + |
2333 | + Authors : Jeremy Wootten <jeremy@elementary.org> |
2334 | +*/ |
2335 | + |
2336 | + |
2337 | +namespace Marlin { |
2338 | + public abstract class AbstractEditableLabel : Gtk.Frame, Gtk.Editable, Gtk.CellEditable { |
2339 | + |
2340 | + public bool editing_canceled { get; set; } |
2341 | + public bool small_size { get; set; } |
2342 | + public float yalign {get; set;} |
2343 | + public float xalign {get; set;} |
2344 | + public string original_name; |
2345 | + public bool draw_outline {get; set;} |
2346 | + |
2347 | + public Gtk.Widget editable_widget; |
2348 | + |
2349 | + public AbstractEditableLabel () { |
2350 | + editable_widget = create_editable_widget (); |
2351 | + add (editable_widget); |
2352 | + show_all (); |
2353 | + get_real_editable ().key_press_event.connect (on_key_press_event); |
2354 | + } |
2355 | + |
2356 | + public bool on_key_press_event (Gdk.EventKey event) { |
2357 | + bool control_pressed = ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0); |
2358 | + switch (event.keyval) { |
2359 | + case Gdk.Key.Return: |
2360 | + case Gdk.Key.KP_Enter: |
2361 | + editing_canceled = false; |
2362 | + editing_done (); |
2363 | + remove_widget (); |
2364 | + break; |
2365 | + |
2366 | + case Gdk.Key.Escape: |
2367 | + editing_canceled = true; |
2368 | + editing_done (); |
2369 | + remove_widget (); |
2370 | + break; |
2371 | + |
2372 | + case Gdk.Key.z: |
2373 | + if (control_pressed) |
2374 | + set_text (original_name); |
2375 | + else |
2376 | + return false; |
2377 | + |
2378 | + break; |
2379 | + |
2380 | + default: |
2381 | + return false; |
2382 | + } |
2383 | + return true; |
2384 | + } |
2385 | + |
2386 | + |
2387 | + public virtual void set_text (string text) { |
2388 | + original_name = text; |
2389 | + } |
2390 | + |
2391 | + public virtual void set_line_wrap (bool wrap) {} |
2392 | + public virtual void set_line_wrap_mode (Pango.WrapMode mode) {} |
2393 | + public virtual void set_justify (Gtk.Justification jtype) {} |
2394 | + public virtual void set_padding (int xpad, int ypad) {} |
2395 | + |
2396 | + public abstract new void set_size_request (int width, int height); |
2397 | + public abstract Gtk.Widget create_editable_widget (); |
2398 | + public abstract string get_text (); |
2399 | + public abstract void select_region (int start_pos, int end_pos); |
2400 | + public abstract void do_delete_text (int start_pos, int end_pos); |
2401 | + public abstract void do_insert_text (string new_text, int new_text_length, ref int position); |
2402 | + public abstract string get_chars (int start_pos, int end_pos); |
2403 | + public abstract int get_position (); |
2404 | + public abstract bool get_selection_bounds (out int start_pos, out int end_pos); |
2405 | + public abstract void set_position (int position); |
2406 | + public abstract Gtk.Widget get_real_editable (); |
2407 | + |
2408 | + |
2409 | + /** CellEditable interface */ |
2410 | + /* modified gtk+-3.0.vapi required */ |
2411 | + public virtual void start_editing (Gdk.Event? event) {} |
2412 | + } |
2413 | +} |
2414 | |
2415 | === modified file 'src/Application.vala' |
2416 | --- src/Application.vala 2014-06-06 18:51:14 +0000 |
2417 | +++ src/Application.vala 2014-11-22 15:05:49 +0000 |
2418 | @@ -26,14 +26,15 @@ |
2419 | |
2420 | private VolumeMonitor volume_monitor; |
2421 | private Marlin.Progress.UIHandler progress_handler; |
2422 | - private Marlin.Clipboard.Manager clipboard; |
2423 | + private Marlin.ClipboardManager clipboard; |
2424 | private Marlin.Thumbnailer thumbnailer; |
2425 | |
2426 | private const int MARLIN_ACCEL_MAP_SAVE_DELAY = 15; |
2427 | - private bool save_of_accel_map_requested = false; |
2428 | |
2429 | public int window_count { get; private set; } |
2430 | |
2431 | + bool quitting = false; |
2432 | + |
2433 | construct { |
2434 | /* Needed by Glib.Application */ |
2435 | this.application_id = "org.pantheon.files"; //Ensures an unique instance. |
2436 | @@ -83,7 +84,6 @@ |
2437 | message ("Report any issues/bugs you might find to http://bugs.launchpad.net/pantheon-files"); |
2438 | |
2439 | init_schemas (); |
2440 | - init_gtk_accels (); |
2441 | |
2442 | Gtk.IconTheme.get_default ().changed.connect (() => { |
2443 | Marlin.IconInfo.clear_caches (); |
2444 | @@ -91,11 +91,9 @@ |
2445 | |
2446 | Notify.init (Config.GETTEXT_PACKAGE); |
2447 | this.progress_handler = new Marlin.Progress.UIHandler (); |
2448 | - this.clipboard = new Marlin.Clipboard.Manager.get_for_display (Gdk.Display.get_default ()); |
2449 | + this.clipboard = new Marlin.ClipboardManager.get_for_display (Gdk.Display.get_default ()); |
2450 | this.thumbnailer = Marlin.Thumbnailer.get (); |
2451 | |
2452 | - tags = new Marlin.View.Tags (); |
2453 | - |
2454 | plugins = new Marlin.PluginManager (Config.PLUGIN_DIR); |
2455 | |
2456 | /* TODO move the volume manager here? */ |
2457 | @@ -112,6 +110,10 @@ |
2458 | this.window_removed.connect (() => {window_count--;}); |
2459 | } |
2460 | |
2461 | + public unowned Marlin.ClipboardManager get_clipboard_manager () { |
2462 | + return this.clipboard; |
2463 | + } |
2464 | + |
2465 | public override int command_line (ApplicationCommandLine cmd) { |
2466 | this.hold (); |
2467 | int result = _command_line (cmd); |
2468 | @@ -195,7 +197,7 @@ |
2469 | |
2470 | /* Open application */ |
2471 | if (create_new_window) |
2472 | - create_window (File.new_for_path (Environment.get_home_dir ()), Gdk.Screen.get_default ()); |
2473 | + create_window (); |
2474 | else if (open_in_tab) |
2475 | open_tabs (files); |
2476 | else |
2477 | @@ -212,34 +214,23 @@ |
2478 | } |
2479 | |
2480 | public new void quit () { |
2481 | - foreach (var window in this.get_windows ()) |
2482 | - window.destroy (); |
2483 | - } |
2484 | - |
2485 | - public void create_window (File location, Gdk.Screen screen) { |
2486 | - open_window (location, screen); |
2487 | + /* Protect against holding Ctrl-Q down */ |
2488 | + if (quitting) |
2489 | + return; |
2490 | + |
2491 | + quitting = true; |
2492 | + unowned List<Gtk.Window> window_list = this.get_windows (); |
2493 | + window_list.@foreach ((window) => { |
2494 | + ((Marlin.View.Window)window).quit (); |
2495 | + }); |
2496 | + |
2497 | + base.quit (); |
2498 | } |
2499 | |
2500 | private void mount_removed_callback (VolumeMonitor monitor, Mount mount) { |
2501 | - /* Check and see if any of the open windows are displaying contents from the unmounted mount */ |
2502 | - unowned List<Gtk.Window> window_list = this.get_windows (); |
2503 | - File root = mount.get_root (); |
2504 | - |
2505 | - /* Check each slot from each window, loading home for current tabs and closing the rest */ |
2506 | - foreach (Gtk.Window window in window_list) { |
2507 | - var marlin_window = window as Marlin.View.Window; |
2508 | - List<Gtk.Widget> pages = marlin_window.tabs.get_children (); |
2509 | - |
2510 | - foreach (var page in pages) { |
2511 | - var view_container = page as Marlin.View.ViewContainer; |
2512 | - File location = view_container.slot.location; |
2513 | - if (location == null || location.has_prefix (root) || location.equal (root)) { |
2514 | - if (view_container == marlin_window.current_tab) |
2515 | - view_container.path_changed (File.new_for_path (Environment.get_home_dir ())); |
2516 | - else |
2517 | - marlin_window.remove_tab (view_container); |
2518 | - } |
2519 | - } |
2520 | + /* Notify each window */ |
2521 | + foreach (var window in this.get_windows ()) { |
2522 | + ((Marlin.View.Window)window).mount_removed (mount); |
2523 | } |
2524 | } |
2525 | |
2526 | @@ -252,44 +243,13 @@ |
2527 | |
2528 | /* Bind settings with GOFPreferences */ |
2529 | Preferences.settings.bind ("show-hiddenfiles", |
2530 | - GOF.Preferences.get_default (), "show-hidden-files", 0); |
2531 | + GOF.Preferences.get_default (), "show-hidden-files", GLib.SettingsBindFlags.DEFAULT); |
2532 | Preferences.settings.bind ("confirm-trash", |
2533 | - GOF.Preferences.get_default (), "confirm-trash", 0); |
2534 | + GOF.Preferences.get_default (), "confirm-trash", GLib.SettingsBindFlags.DEFAULT); |
2535 | Preferences.settings.bind ("date-format", |
2536 | - GOF.Preferences.get_default (), "date-format", 0); |
2537 | + GOF.Preferences.get_default (), "date-format", GLib.SettingsBindFlags.DEFAULT); |
2538 | Preferences.settings.bind ("interpret-desktop-files", |
2539 | - GOF.Preferences.get_default (), "interpret-desktop-files", 0); |
2540 | - } |
2541 | - |
2542 | - /* Load accelerator map, and register save callback */ |
2543 | - private void init_gtk_accels () { |
2544 | - string accel_map_filename = Marlin.get_accel_map_file (); |
2545 | - if (accel_map_filename != null) { |
2546 | - Gtk.AccelMap.load (accel_map_filename); |
2547 | - } |
2548 | - |
2549 | - Gtk.AccelMap.get ().changed.connect (() => { |
2550 | - if (!save_of_accel_map_requested) { |
2551 | - save_of_accel_map_requested = true; |
2552 | - Timeout.add_seconds (MARLIN_ACCEL_MAP_SAVE_DELAY, |
2553 | - save_accel_map); |
2554 | - } |
2555 | - }); |
2556 | - } |
2557 | - |
2558 | - private bool save_accel_map () { |
2559 | - if (save_of_accel_map_requested) { |
2560 | - string accel_map_filename = Marlin.get_accel_map_file (); |
2561 | - if (accel_map_filename != null) |
2562 | - Gtk.AccelMap.save (accel_map_filename); |
2563 | - save_of_accel_map_requested = false; |
2564 | - } |
2565 | - |
2566 | - return false; |
2567 | - } |
2568 | - |
2569 | - private void open_window (File location, Gdk.Screen screen = Gdk.Screen.get_default ()) { |
2570 | - (add_view_window (screen)).add_tab (location); |
2571 | + GOF.Preferences.get_default (), "interpret-desktop-files", GLib.SettingsBindFlags.DEFAULT); |
2572 | } |
2573 | |
2574 | private void open_windows (File[]? files) { |
2575 | @@ -302,6 +262,24 @@ |
2576 | } |
2577 | } |
2578 | |
2579 | + public void create_window (File location = File.new_for_path (Environment.get_home_dir ()), |
2580 | + Gdk.Screen screen = Gdk.Screen.get_default (), |
2581 | + Marlin.ViewMode viewmode = Marlin.ViewMode.PREFERRED) { |
2582 | + |
2583 | + open_window (location, screen, viewmode); |
2584 | + } |
2585 | + |
2586 | + private void open_window (File? location, Gdk.Screen screen = Gdk.Screen.get_default (), Marlin.ViewMode viewmode = Marlin.ViewMode.PREFERRED) { |
2587 | + (add_view_window (screen)).add_tab (location, viewmode); |
2588 | + } |
2589 | + |
2590 | + private Marlin.View.Window add_view_window (Gdk.Screen screen) { |
2591 | + var window = new Marlin.View.Window (this, screen); |
2592 | + this.add_window (window as Gtk.Window); |
2593 | + plugins.interface_loaded (window as Gtk.Widget); |
2594 | + return window; |
2595 | + } |
2596 | + |
2597 | private void open_tabs (File[]? files, Gdk.Screen screen = Gdk.Screen.get_default ()) { |
2598 | Marlin.View.Window window = null; |
2599 | |
2600 | @@ -316,22 +294,15 @@ |
2601 | if (!Preferences.settings.get_boolean ("restore-tabs") || window.restore_tabs () < 1) { |
2602 | /* Open a tab pointing at the default location if no tabs restored*/ |
2603 | var location = File.new_for_path (Environment.get_home_dir ()); |
2604 | - window.add_tab (location); |
2605 | + window.add_tab (location, Marlin.ViewMode.PREFERRED); |
2606 | } |
2607 | } else { |
2608 | /* Open tabs at each requested location */ |
2609 | foreach (var file in files) |
2610 | - window.add_tab (file); |
2611 | + window.add_tab (file, Marlin.ViewMode.PREFERRED); |
2612 | } |
2613 | } |
2614 | |
2615 | - private Marlin.View.Window add_view_window (Gdk.Screen screen) { |
2616 | - var window = new Marlin.View.Window (this, screen, true); |
2617 | - this.add_window (window as Gtk.Window); |
2618 | - plugins.interface_loaded (window as Gtk.Widget); |
2619 | - return window; |
2620 | - } |
2621 | - |
2622 | private bool windows_exist () { |
2623 | unowned List<weak Gtk.Window> windows = this.get_windows (); |
2624 | return (windows != null && windows.data != null); |
2625 | |
2626 | === modified file 'src/BookmarkList.vala' |
2627 | --- src/BookmarkList.vala 2014-07-22 02:54:40 +0000 |
2628 | +++ src/BookmarkList.vala 2014-11-22 15:05:49 +0000 |
2629 | @@ -88,6 +88,11 @@ |
2630 | save_bookmarks_file (); |
2631 | } |
2632 | |
2633 | + public void insert_uri_at_end (string uri) { |
2634 | + append_internal (new Bookmark.from_uri (uri, null)); |
2635 | + save_bookmarks_file (); |
2636 | + } |
2637 | + |
2638 | public void insert_uris (GLib.List<string> uris, uint index) { |
2639 | uris.@foreach ((uri) => { |
2640 | insert_item_internal (new Bookmark.from_uri (uri, null), index); |
2641 | |
2642 | === modified file 'src/CMakeLists.txt' |
2643 | --- src/CMakeLists.txt 2014-08-05 22:40:12 +0000 |
2644 | +++ src/CMakeLists.txt 2014-11-22 15:05:49 +0000 |
2645 | @@ -48,31 +48,40 @@ |
2646 | Bookmark.vala |
2647 | BookmarkList.vala |
2648 | ConnectServerOperation.vala |
2649 | + DndHandler.vala |
2650 | + AbstractEditableLabel.vala |
2651 | + SingleLineEditableLabel.vala |
2652 | + MultiLineEditableLabel.vala |
2653 | main.vala |
2654 | marlin-deep-count.vala |
2655 | MimeActions.vala |
2656 | ProgressInfoWidget.vala |
2657 | ProgressUIHandler.vala |
2658 | + TextRenderer.vala |
2659 | QuicklistHandler.vala |
2660 | + View/ColumnView.vala |
2661 | + View/AbstractTreeView.vala |
2662 | + View/IconView.vala |
2663 | + View/ListView.vala |
2664 | ZeitgeistManager.vala |
2665 | View/DiskRenderer.vala |
2666 | View/IconSpinnerRenderer.vala |
2667 | View/DirectoryNotFound.vala |
2668 | + View/AbstractDirectoryView.vala |
2669 | View/SearchResults.vala |
2670 | View/Window.vala |
2671 | View/Resources.vala |
2672 | - View/DbusTags.vala |
2673 | View/ViewContainer.vala |
2674 | View/OverlayBar.vala |
2675 | View/PropertiesWindow.vala |
2676 | View/Browser.vala |
2677 | - View/ViewMode.vala |
2678 | View/LocationBar.vala |
2679 | View/Sidebar.vala |
2680 | + View/Slot.vala |
2681 | + View/Miller.vala |
2682 | View/Chrome/TopMenu.vala |
2683 | View/Chrome/ButtonWithMenu.vala |
2684 | View/Chrome/ViewSwicher.vala |
2685 | - View/Chrome/ColorWidget.vala |
2686 | View/Chrome/XsEntry.vala |
2687 | View/Chrome/ImgEventBox.vala |
2688 | PACKAGES |
2689 | @@ -104,35 +113,45 @@ |
2690 | Bookmark.vala |
2691 | BookmarkList.vala |
2692 | ConnectServerOperation.vala |
2693 | + DndHandler.vala |
2694 | + AbstractEditableLabel.vala |
2695 | + SingleLineEditableLabel.vala |
2696 | + MultiLineEditableLabel.vala |
2697 | main.vala |
2698 | marlin-deep-count.vala |
2699 | MimeActions.vala |
2700 | ProgressInfoWidget.vala |
2701 | ProgressUIHandler.vala |
2702 | + TextRenderer.vala |
2703 | + View/ColumnView.vala |
2704 | + View/AbstractTreeView.vala |
2705 | + View/IconView.vala |
2706 | + View/ListView.vala |
2707 | ZeitgeistManager.vala |
2708 | View/SearchResults.vala |
2709 | View/DiskRenderer.vala |
2710 | View/DirectoryNotFound.vala |
2711 | + View/AbstractDirectoryView.vala |
2712 | View/Window.vala |
2713 | View/Resources.vala |
2714 | - View/DbusTags.vala |
2715 | View/ViewContainer.vala |
2716 | View/IconSpinnerRenderer.vala |
2717 | View/OverlayBar.vala |
2718 | View/PropertiesWindow.vala |
2719 | View/Browser.vala |
2720 | - View/ViewMode.vala |
2721 | View/LocationBar.vala |
2722 | View/Sidebar.vala |
2723 | + View/Slot.vala |
2724 | + View/Miller.vala |
2725 | View/Chrome/TopMenu.vala |
2726 | View/Chrome/ButtonWithMenu.vala |
2727 | View/Chrome/ViewSwicher.vala |
2728 | - View/Chrome/ColorWidget.vala |
2729 | View/Chrome/XsEntry.vala |
2730 | View/Chrome/ImgEventBox.vala |
2731 | PACKAGES |
2732 | gtk+-3.0 |
2733 | gio-2.0 |
2734 | + pango |
2735 | posix |
2736 | gee-0.8 |
2737 | granite |
2738 | @@ -154,23 +173,10 @@ |
2739 | ENDIF (WITH_UNITY AND UNITY_FOUND) |
2740 | |
2741 | add_executable (../pantheon-files |
2742 | - eel-editable-label.c |
2743 | marlin-enum-types.c |
2744 | - marlin-dnd.c |
2745 | marlin-clipboard-manager.c |
2746 | - marlin-window-columns.c |
2747 | - gof-window-slot.c |
2748 | marlin-thumbnailer.c |
2749 | marlin-icon-renderer.c |
2750 | - marlin-text-renderer.c |
2751 | - marlin-cell-renderer-text-ellipsized.c |
2752 | - fm-directory-view.c |
2753 | - exo-icon-view.c |
2754 | - exo-tree-view.c |
2755 | - fm-abstract-icon-view.c |
2756 | - fm-icon-view.c |
2757 | - fm-list-view.c |
2758 | - fm-columns-view.c |
2759 | marlin-connect-server-dialog.c |
2760 | ${VALA_C} ) |
2761 | |
2762 | @@ -184,5 +190,5 @@ |
2763 | ENDIF (WITH_UNITY AND UNITY_FOUND) |
2764 | |
2765 | install (TARGETS ../pantheon-files RUNTIME DESTINATION bin) |
2766 | -install (FILES pantheon-files-ui.xml fm-directory-view-ui.xml fm-icon-view-ui.xml DESTINATION ${UI_DIR}) |
2767 | +install (FILES View/directory_view_popup.ui DESTINATION ${UI_DIR}) |
2768 | include (Tests) |
2769 | |
2770 | === added file 'src/DndHandler.vala' |
2771 | --- src/DndHandler.vala 1970-01-01 00:00:00 +0000 |
2772 | +++ src/DndHandler.vala 2014-11-22 15:05:49 +0000 |
2773 | @@ -0,0 +1,272 @@ |
2774 | +/* |
2775 | + * DndHandler.vala |
2776 | + * |
2777 | + * Copyright 2014 jeremy <jeremy@jeremy-MM061> |
2778 | + * |
2779 | + * This program is free software; you can redistribute it and/or modify |
2780 | + * it under the terms of the GNU General Public License as published by |
2781 | + * the Free Software Foundation; either version 2 of the License, or |
2782 | + * (at your option) any later version. |
2783 | + * |
2784 | + * This program is distributed in the hope that it will be useful, |
2785 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2786 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2787 | + * GNU General Public License for more details. |
2788 | + * |
2789 | + * You should have received a copy of the GNU General Public License |
2790 | + * along with this program; if not, write to the Free Software |
2791 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
2792 | + * MA 02110-1301, USA. |
2793 | + * |
2794 | + * |
2795 | + */ |
2796 | + |
2797 | +namespace FM { |
2798 | + public class DndHandler : GLib.Object { |
2799 | + Gdk.DragAction chosen = Gdk.DragAction.DEFAULT; |
2800 | + |
2801 | + public DndHandler () {} |
2802 | + |
2803 | + public bool dnd_perform (Gtk.Widget widget, |
2804 | + GOF.File drop_target, |
2805 | + GLib.List<GLib.File> drop_file_list, |
2806 | + Gdk.DragAction action) { |
2807 | + |
2808 | + if (drop_target.is_folder ()) { |
2809 | + Marlin.FileOperations.copy_move (drop_file_list, |
2810 | + null, |
2811 | + drop_target.get_target_location (), |
2812 | + action, |
2813 | + widget, |
2814 | + (void*)dnd_done, |
2815 | + null); |
2816 | + return true; |
2817 | + } else if (drop_target.is_executable ()) { |
2818 | + GLib.Error error; |
2819 | + if (!drop_target.execute (widget.get_screen (), drop_file_list, out error)) { |
2820 | + Eel.show_error_dialog (_("Failed to execute \"%s\"").printf (drop_target.get_display_name ()), |
2821 | + error.message, |
2822 | + null); |
2823 | + return false; |
2824 | + } else |
2825 | + return true; |
2826 | + } |
2827 | + return false; |
2828 | + } |
2829 | + |
2830 | + private void dnd_done (GLib.List<GLib.File> files, void* data) {} |
2831 | + |
2832 | + public Gdk.DragAction? drag_drop_action_ask (Gtk.Widget dest_widget, |
2833 | + Gtk.ApplicationWindow win, |
2834 | + Gdk.DragAction possible_actions) { |
2835 | + this.chosen = Gdk.DragAction.DEFAULT; |
2836 | + add_action (win); |
2837 | + var ask_menu = build_menu (possible_actions); |
2838 | + ask_menu.set_screen (dest_widget.get_screen ()); |
2839 | + ask_menu.show_all (); |
2840 | + var loop = new GLib.MainLoop (null, false); |
2841 | + |
2842 | + ask_menu.deactivate.connect (() => { |
2843 | + if (loop.is_running ()) |
2844 | + loop.quit (); |
2845 | + |
2846 | + remove_action (win); |
2847 | + }); |
2848 | + |
2849 | + ask_menu.popup (null, null, null, 0, Gdk.CURRENT_TIME); |
2850 | + loop.run (); |
2851 | + Gtk.grab_remove (ask_menu); |
2852 | + |
2853 | + return this.chosen; |
2854 | + } |
2855 | + |
2856 | + private void add_action (Gtk.ApplicationWindow win) { |
2857 | + var action = new GLib.SimpleAction ("choice", GLib.VariantType.STRING); |
2858 | + action.activate.connect (this.on_choice); |
2859 | + |
2860 | + win.add_action (action); |
2861 | + } |
2862 | + |
2863 | + private void remove_action (Gtk.ApplicationWindow win) { |
2864 | + win.remove_action ("choice"); |
2865 | + } |
2866 | + |
2867 | + private Gtk.Menu build_menu (Gdk.DragAction possible_actions) { |
2868 | + var menu = new Gtk.Menu (); |
2869 | + |
2870 | + build_and_append_menu_item (menu, _("Move Here"), Gdk.DragAction.MOVE, possible_actions); |
2871 | + build_and_append_menu_item (menu, _("Copy Here"), Gdk.DragAction.COPY, possible_actions); |
2872 | + build_and_append_menu_item (menu, _("Link Here"), Gdk.DragAction.LINK, possible_actions); |
2873 | + |
2874 | + menu.append (new Gtk.SeparatorMenuItem ()); |
2875 | + menu.append (new Gtk.MenuItem.with_label (_("Cancel"))); |
2876 | + |
2877 | + return menu; |
2878 | + } |
2879 | + |
2880 | + private void build_and_append_menu_item (Gtk.Menu menu, string label, Gdk.DragAction? action, Gdk.DragAction possible_actions) { |
2881 | + if ((possible_actions & action) != 0) { |
2882 | + var item = new Gtk.MenuItem.with_label (label); |
2883 | + |
2884 | + item.activate.connect (() => { |
2885 | + this.chosen = action; |
2886 | + }); |
2887 | + |
2888 | + menu.append (item); |
2889 | + } |
2890 | + } |
2891 | + |
2892 | + public void on_choice (GLib.Variant? param) { |
2893 | + if (param == null || !param.is_of_type (GLib.VariantType.STRING)) { |
2894 | + critical ("Invalid variant type in DndHandler Menu"); |
2895 | + return; |
2896 | + } |
2897 | + |
2898 | + string choice = param.get_string (); |
2899 | + |
2900 | + switch (choice) { |
2901 | + case "move": |
2902 | + this.chosen = Gdk.DragAction.MOVE; |
2903 | + break; |
2904 | + case "copy": |
2905 | + this.chosen = Gdk.DragAction.COPY; |
2906 | + break; |
2907 | + case "link": |
2908 | + this.chosen = Gdk.DragAction.LINK; |
2909 | + break; |
2910 | + case "background": /* not implemented yet */ |
2911 | + case "cancel": |
2912 | + default: |
2913 | + this.chosen = Gdk.DragAction.DEFAULT; |
2914 | + break; |
2915 | + } |
2916 | + } |
2917 | + |
2918 | + public string? get_source_filename (Gdk.DragContext context) { |
2919 | + uchar []? data = null; |
2920 | + Gdk.Atom property_name = Gdk.Atom.intern_static_string ("XdndDirectSave0"); |
2921 | + Gdk.Atom property_type = Gdk.Atom.intern_static_string ("text/plain"); |
2922 | + |
2923 | + bool exists = Gdk.property_get (context.get_source_window (), |
2924 | + property_name, |
2925 | + property_type, |
2926 | + 0, /* offset into property to start getting */ |
2927 | + 1024, /* max bytes of data to retrieve */ |
2928 | + 0, /* do not delete after retrieving */ |
2929 | + null, null, /* actual property type and format got disregarded */ |
2930 | + out data |
2931 | + ); |
2932 | + |
2933 | + if (exists && data != null) { |
2934 | + string name = data_to_string (data); |
2935 | + if (GLib.Path.DIR_SEPARATOR.to_string () in name) { |
2936 | + warning ("invalid source filename"); |
2937 | + return null; /* not a valid filename */ |
2938 | + } else |
2939 | + return name; |
2940 | + } else { |
2941 | + warning ("source file does not exist"); |
2942 | + return null; |
2943 | + } |
2944 | + } |
2945 | + |
2946 | + public void set_source_uri (Gdk.DragContext context, string uri) { |
2947 | + debug ("DNDHANDLER: set source uri to %s", uri); |
2948 | + Gdk.Atom property_name = Gdk.Atom.intern_static_string ("XdndDirectSave0"); |
2949 | + Gdk.Atom property_type = Gdk.Atom.intern_static_string ("text/plain"); |
2950 | + |
2951 | + Gdk.property_change (context.get_source_window (), |
2952 | + property_name, |
2953 | + property_type, |
2954 | + 8, |
2955 | + Gdk.PropMode.REPLACE, |
2956 | + uri.data, |
2957 | + uri.length); |
2958 | + } |
2959 | + |
2960 | + public bool handle_xdnddirectsave (Gdk.DragContext context, |
2961 | + GOF.File drop_target, |
2962 | + Gtk.SelectionData selection) { |
2963 | + bool success = false; |
2964 | + |
2965 | + if (selection.get_length () == 1 && selection.get_format () == 8) { |
2966 | + uchar result = selection.get_data ()[0]; |
2967 | + |
2968 | + switch (result) { |
2969 | + case 'F': |
2970 | + /* No fallback for XdndDirectSave stage (3), result "F" ("Failed") yet */ |
2971 | + break; |
2972 | + case 'S': |
2973 | + /* XdndDirectSave "Success" */ |
2974 | + success = true; |
2975 | + break; |
2976 | + default: |
2977 | + warning ("Unhandled XdndDirectSave result %s", result.to_string ()); |
2978 | + break; |
2979 | + } |
2980 | + } |
2981 | + |
2982 | + if (!success) |
2983 | + set_source_uri (context, ""); |
2984 | + |
2985 | + return success; |
2986 | + } |
2987 | + |
2988 | + public bool handle_netscape_url (Gdk.DragContext context, GOF.File drop_target, Gtk.SelectionData selection) { |
2989 | + string [] parts = (selection.get_text ()).split ("\n"); |
2990 | + |
2991 | + /* _NETSCAPE_URL looks like this: "$URL\n$TITLE" - should be 2 parts */ |
2992 | + if (parts.length != 2) |
2993 | + return false; |
2994 | + |
2995 | + /* NETSCAPE URLs are not currently handled. No current bug reports */ |
2996 | + return false; |
2997 | + } |
2998 | + |
2999 | + public bool handle_file_drag_actions (Gtk.Widget dest_widget, |
3000 | + Gtk.ApplicationWindow win, |
3001 | + Gdk.DragContext context, |
3002 | + GOF.File drop_target, |
3003 | + GLib.List<GLib.File> drop_file_list, |
3004 | + Gdk.DragAction possible_actions, |
3005 | + Gdk.DragAction suggested_action, |
3006 | + uint32 timestamp) { |
3007 | + bool success = false; |
3008 | + Gdk.DragAction action = suggested_action; |
3009 | + |
3010 | + if ((possible_actions & Gdk.DragAction.ASK) != 0) |
3011 | + action = drag_drop_action_ask (dest_widget, win, possible_actions); |
3012 | + |
3013 | + if (action != Gdk.DragAction.DEFAULT) { |
3014 | + success = dnd_perform (dest_widget, |
3015 | + drop_target, |
3016 | + drop_file_list, |
3017 | + action); |
3018 | + } |
3019 | + return success; |
3020 | + } |
3021 | + |
3022 | + |
3023 | + public bool selection_data_is_uri_list (Gtk.SelectionData selection_data, uint info, out string? text) { |
3024 | + text = null; |
3025 | + |
3026 | + if (info == AbstractDirectoryView.TargetType.TEXT_URI_LIST && |
3027 | + selection_data.get_format () == 8 && |
3028 | + selection_data.get_length () > 0) { |
3029 | + |
3030 | + text = data_to_string (selection_data.get_data_with_length ()); |
3031 | + } |
3032 | + debug ("DNDHANDLER selection data is uri list returning %s", (text != null).to_string ()); |
3033 | + return (text != null); |
3034 | + } |
3035 | + |
3036 | + private string data_to_string (uchar [] cdata) { |
3037 | + var sb = new StringBuilder (""); |
3038 | + |
3039 | + foreach (uchar u in cdata) |
3040 | + sb.append_c ((char)u); |
3041 | + |
3042 | + return sb.str; |
3043 | + } |
3044 | + } |
3045 | +} |
3046 | |
3047 | === modified file 'src/MimeActions.vala' |
3048 | --- src/MimeActions.vala 2014-01-11 14:48:15 +0000 |
3049 | +++ src/MimeActions.vala 2014-11-22 15:05:49 +0000 |
3050 | @@ -23,6 +23,7 @@ |
3051 | public class Marlin.MimeActions { |
3052 | |
3053 | public static AppInfo? get_default_application_for_file (GOF.File file) { |
3054 | + |
3055 | AppInfo app = file.get_default_handler (); |
3056 | |
3057 | if (app == null) { |
3058 | @@ -35,16 +36,20 @@ |
3059 | return app; |
3060 | } |
3061 | |
3062 | - public static AppInfo? get_default_application_for_files (List<GOF.File> files) { |
3063 | + public static AppInfo? get_default_application_for_files (GLib.List<unowned GOF.File> files) { |
3064 | assert (files != null); |
3065 | + /* Need to make a new list to avoid corrupting the selection */ |
3066 | + unowned GLib.List<GOF.File> sorted_files = null; |
3067 | + files.@foreach ((file) => { |
3068 | + sorted_files.prepend (file); |
3069 | + }); |
3070 | |
3071 | - List<GOF.File> sorted_files = files.copy (); |
3072 | sorted_files.sort (file_compare_by_mime_type); |
3073 | |
3074 | - AppInfo app = null; |
3075 | - GOF.File previous_file = null; |
3076 | + AppInfo? app = null; |
3077 | + GOF.File? previous_file = null; |
3078 | |
3079 | - foreach (var file in sorted_files) { |
3080 | + foreach (GOF.File file in sorted_files) { |
3081 | if (previous_file == null) { |
3082 | app = get_default_application_for_file (file); |
3083 | previous_file = file; |
3084 | @@ -67,11 +72,11 @@ |
3085 | |
3086 | previous_file = file; |
3087 | } |
3088 | - |
3089 | return app; |
3090 | } |
3091 | |
3092 | public static List<AppInfo>? get_applications_for_file (GOF.File file) { |
3093 | + |
3094 | List<AppInfo> result = AppInfo.get_all_for_type (file.get_ftype ()); |
3095 | string uri_scheme = file.location.get_uri_scheme (); |
3096 | |
3097 | @@ -109,16 +114,19 @@ |
3098 | return result; |
3099 | } |
3100 | |
3101 | - public static List<AppInfo>? get_applications_for_files (List<GOF.File> files) { |
3102 | + public static List<AppInfo>? get_applications_for_files (GLib.List<unowned GOF.File> files) { |
3103 | assert (files != null); |
3104 | - |
3105 | - List<GOF.File> sorted_files = files.copy (); |
3106 | + /* Need to make a new list to avoid corrupting the selection */ |
3107 | + unowned GLib.List<GOF.File> sorted_files = null; |
3108 | + files.@foreach ((file) => { |
3109 | + sorted_files.prepend (file); |
3110 | + }); |
3111 | sorted_files.sort (file_compare_by_mime_type); |
3112 | |
3113 | List<AppInfo> result = null; |
3114 | - GOF.File previous_file = null; |
3115 | + unowned GOF.File previous_file = null; |
3116 | |
3117 | - foreach (var file in sorted_files) { |
3118 | + foreach (unowned GOF.File file in sorted_files) { |
3119 | if (previous_file == null) { |
3120 | result = get_applications_for_file (file); |
3121 | previous_file = file; |
3122 | |
3123 | === added file 'src/MultiLineEditableLabel.vala' |
3124 | --- src/MultiLineEditableLabel.vala 1970-01-01 00:00:00 +0000 |
3125 | +++ src/MultiLineEditableLabel.vala 2014-11-22 15:05:49 +0000 |
3126 | @@ -0,0 +1,196 @@ |
3127 | +/* |
3128 | + Copyright (C) 2014 elementary Developers |
3129 | + |
3130 | + This program is free software: you can redistribute it and/or modify it |
3131 | + under the terms of the GNU Lesser General Public License version 3, as published |
3132 | + by the Free Software Foundation. |
3133 | + |
3134 | + This program is distributed in the hope that it will be useful, but |
3135 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
3136 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3137 | + PURPOSE. See the GNU General Public License for more details. |
3138 | + |
3139 | + You should have received a copy of the GNU General Public License along |
3140 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
3141 | + |
3142 | + Authors : Jeremy Wootten <jeremy@elementary.org> |
3143 | +*/ |
3144 | + |
3145 | +namespace Marlin { |
3146 | + public class MultiLineEditableLabel : AbstractEditableLabel { |
3147 | + |
3148 | + protected Gtk.ScrolledWindow scrolled_window; |
3149 | + protected Gtk.TextView textview; |
3150 | + |
3151 | + public MultiLineEditableLabel () {} |
3152 | + |
3153 | + public override Gtk.Widget create_editable_widget () { |
3154 | + textview = new Gtk.TextView (); |
3155 | + scrolled_window = new Gtk.ScrolledWindow (null, null); |
3156 | + scrolled_window.add (textview); |
3157 | + return scrolled_window as Gtk.Widget; |
3158 | + } |
3159 | + |
3160 | + public override Gtk.Widget get_real_editable () { |
3161 | + return textview; |
3162 | + } |
3163 | + |
3164 | + public override void set_text (string text) { |
3165 | + textview.get_buffer ().set_text (text); |
3166 | + original_name = text; |
3167 | + } |
3168 | + |
3169 | + public override void set_line_wrap (bool wrap) { |
3170 | + if (!wrap) |
3171 | + textview.set_wrap_mode (Gtk.WrapMode.NONE); |
3172 | + else |
3173 | + textview.set_wrap_mode (Gtk.WrapMode.CHAR); |
3174 | + } |
3175 | + |
3176 | + public override void set_line_wrap_mode (Pango.WrapMode mode) { |
3177 | + switch (mode) { |
3178 | + case Pango.WrapMode.CHAR: |
3179 | + textview.set_wrap_mode (Gtk.WrapMode.CHAR); |
3180 | + break; |
3181 | + |
3182 | + case Pango.WrapMode.WORD: |
3183 | + textview.set_wrap_mode (Gtk.WrapMode.WORD); |
3184 | + break; |
3185 | + |
3186 | + case Pango.WrapMode.WORD_CHAR: |
3187 | + textview.set_wrap_mode (Gtk.WrapMode.WORD_CHAR); |
3188 | + break; |
3189 | + |
3190 | + default: |
3191 | + break; |
3192 | + } |
3193 | + } |
3194 | + |
3195 | + public override void set_justify (Gtk.Justification jtype) { |
3196 | + textview.justification = jtype; |
3197 | + } |
3198 | + |
3199 | + public override void set_padding (int xpad, int ypad) { |
3200 | + textview.set_margin_start (xpad); |
3201 | + textview.set_margin_end (xpad); |
3202 | + textview.set_margin_top (ypad); |
3203 | + textview.set_margin_bottom (ypad); |
3204 | + } |
3205 | + |
3206 | + public override string get_text () { |
3207 | + var buffer = textview.get_buffer (); |
3208 | + Gtk.TextIter? start = null; |
3209 | + Gtk.TextIter? end = null; |
3210 | + buffer.get_start_iter (out start); |
3211 | + buffer.get_end_iter (out end); |
3212 | + return buffer.get_text (start, end, false); |
3213 | + } |
3214 | + |
3215 | + /** Gtk.Editable interface */ |
3216 | + |
3217 | + public override void select_region (int start_pos, int end_pos) { |
3218 | + var buffer = textview.get_buffer (); |
3219 | + Gtk.TextIter? ins = null; |
3220 | + Gtk.TextIter? bound = null; |
3221 | + |
3222 | + buffer.get_iter_at_offset (out ins, start_pos); |
3223 | + |
3224 | + if (end_pos > 0) |
3225 | + buffer.get_iter_at_offset (out bound, end_pos); |
3226 | + else |
3227 | + buffer.get_end_iter (out bound); |
3228 | + |
3229 | + buffer.select_range (ins, bound); |
3230 | + textview.grab_focus (); |
3231 | + } |
3232 | + |
3233 | + public override void do_delete_text (int start_pos, int end_pos) { |
3234 | + var buffer = textview.get_buffer (); |
3235 | + Gtk.TextIter? start = null; |
3236 | + Gtk.TextIter? end = null; |
3237 | + |
3238 | + buffer.get_iter_at_offset (out start, start_pos); |
3239 | + |
3240 | + if (end_pos > 0) |
3241 | + buffer.get_iter_at_offset (out end, end_pos); |
3242 | + else |
3243 | + buffer.get_end_iter (out end); |
3244 | + |
3245 | + buffer.delete_range (start, end); |
3246 | + } |
3247 | + |
3248 | + public override void do_insert_text (string new_text, int new_text_length, ref int position) { |
3249 | + var buffer = textview.get_buffer (); |
3250 | + Gtk.TextIter? pos = null; |
3251 | + |
3252 | + buffer.get_iter_at_offset (out pos, position); |
3253 | + buffer.insert (ref pos, new_text, new_text_length); |
3254 | + } |
3255 | + |
3256 | + public override string get_chars (int start_pos, int end_pos) { |
3257 | + var buffer = textview.get_buffer (); |
3258 | + Gtk.TextIter? start = null; |
3259 | + Gtk.TextIter? end = null; |
3260 | + |
3261 | + buffer.get_iter_at_offset (out start, start_pos); |
3262 | + |
3263 | + if (end_pos > 0) |
3264 | + buffer.get_iter_at_offset (out end, end_pos); |
3265 | + else |
3266 | + buffer.get_end_iter (out end); |
3267 | + |
3268 | + return buffer.get_text (start, end, false); |
3269 | + } |
3270 | + |
3271 | + public override int get_position () { |
3272 | + var buffer = textview.get_buffer (); |
3273 | + var mark = buffer.get_insert (); |
3274 | + Gtk.TextIter? iter = null; |
3275 | + buffer.get_iter_at_mark (out iter, mark); |
3276 | + |
3277 | + return iter.get_offset (); |
3278 | + } |
3279 | + |
3280 | + public override bool get_selection_bounds (out int start_pos, out int end_pos) { |
3281 | + var buffer = textview.get_buffer (); |
3282 | + Gtk.TextIter? start = null; |
3283 | + Gtk.TextIter? end = null; |
3284 | + |
3285 | + buffer.get_selection_bounds (out start, out end); |
3286 | + start_pos = start.get_offset (); |
3287 | + end_pos = end.get_offset (); |
3288 | + |
3289 | + return start_pos != end_pos; |
3290 | + } |
3291 | + |
3292 | + public override void set_position (int position) { |
3293 | + var buffer = textview.get_buffer (); |
3294 | + Gtk.TextIter? iter = null; |
3295 | + buffer.get_start_iter (out iter); |
3296 | + iter.set_offset (position); |
3297 | + buffer.place_cursor (iter); |
3298 | + } |
3299 | + |
3300 | + public override bool draw (Cairo.Context cr) { |
3301 | + bool result = base.draw (cr); |
3302 | + if (draw_outline) { |
3303 | + Gtk.Allocation allocation; |
3304 | + Gdk.RGBA color; |
3305 | + Gdk.Rectangle outline; |
3306 | + |
3307 | + get_allocation (out allocation); |
3308 | + color = get_style_context ().get_color (get_state_flags ()); |
3309 | + Gdk.cairo_set_source_rgba (cr, color); |
3310 | + cr.set_line_width (1.0); |
3311 | + outline = {0, 0, allocation.width, allocation.height}; |
3312 | + Gdk.cairo_rectangle (cr, outline); |
3313 | + cr.stroke (); |
3314 | + } |
3315 | + return result; |
3316 | + } |
3317 | + |
3318 | + public override void set_size_request (int width, int height) { |
3319 | + textview.set_size_request (width, height); |
3320 | + } |
3321 | + } |
3322 | +} |
3323 | |
3324 | === added file 'src/SingleLineEditableLabel.vala' |
3325 | --- src/SingleLineEditableLabel.vala 1970-01-01 00:00:00 +0000 |
3326 | +++ src/SingleLineEditableLabel.vala 2014-11-22 15:05:49 +0000 |
3327 | @@ -0,0 +1,104 @@ |
3328 | +/* |
3329 | + Copyright (C) 2014 elementary Developers |
3330 | + |
3331 | + This program is free software: you can redistribute it and/or modify it |
3332 | + under the terms of the GNU Lesser General Public License version 3, as published |
3333 | + by the Free Software Foundation. |
3334 | + |
3335 | + This program is distributed in the hope that it will be useful, but |
3336 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
3337 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3338 | + PURPOSE. See the GNU General Public License for more details. |
3339 | + |
3340 | + You should have received a copy of the GNU General Public License along |
3341 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
3342 | + |
3343 | + Authors : Jeremy Wootten <jeremy@elementary.org> |
3344 | +*/ |
3345 | + |
3346 | +namespace Marlin { |
3347 | + public class SingleLineEditableLabel : AbstractEditableLabel { |
3348 | + |
3349 | + protected Gtk.Entry textview; |
3350 | + |
3351 | + public SingleLineEditableLabel () {} |
3352 | + |
3353 | + public override Gtk.Widget create_editable_widget () { |
3354 | + textview = new Gtk.Entry (); |
3355 | + return textview as Gtk.Widget; |
3356 | + } |
3357 | + |
3358 | + public override Gtk.Widget get_real_editable () { |
3359 | + return textview; |
3360 | + } |
3361 | + |
3362 | + public override void set_text (string text) { |
3363 | + textview.set_text (text); |
3364 | + original_name = text; |
3365 | + } |
3366 | + |
3367 | + |
3368 | + public override void set_justify (Gtk.Justification jtype) { |
3369 | + switch (jtype) { |
3370 | + case Gtk.Justification.LEFT: |
3371 | + textview.set_alignment (0.0f); |
3372 | + break; |
3373 | + |
3374 | + case Gtk.Justification.CENTER: |
3375 | + textview.set_alignment (0.5f); |
3376 | + break; |
3377 | + |
3378 | + case Gtk.Justification.RIGHT: |
3379 | + textview.set_alignment (1.0f); |
3380 | + break; |
3381 | + |
3382 | + default: |
3383 | + textview.set_alignment (0.5f); |
3384 | + break; |
3385 | + } |
3386 | + } |
3387 | + |
3388 | + public override string get_text () { |
3389 | + return textview.get_text (); |
3390 | + } |
3391 | + |
3392 | + /** Gtk.Editable interface */ |
3393 | + |
3394 | + public override void select_region (int start_pos, int end_pos) { |
3395 | + textview.select_region (start_pos, end_pos); |
3396 | + textview.grab_focus (); |
3397 | + } |
3398 | + |
3399 | + public override void do_delete_text (int start_pos, int end_pos) { |
3400 | + textview.delete_text (start_pos, end_pos); |
3401 | + } |
3402 | + |
3403 | + public override void do_insert_text (string new_text, int new_text_length, ref int position) { |
3404 | + textview.insert_text (new_text, new_text_length, ref position); |
3405 | + } |
3406 | + |
3407 | + public override string get_chars (int start_pos, int end_pos) { |
3408 | + return textview.get_chars (start_pos, end_pos); |
3409 | + } |
3410 | + |
3411 | + public override int get_position () { |
3412 | + return textview.get_position (); |
3413 | + } |
3414 | + |
3415 | + public override bool get_selection_bounds (out int start_pos, out int end_pos) { |
3416 | + int start, end; |
3417 | + bool result = textview.get_selection_bounds (out start, out end); |
3418 | + start_pos = start; |
3419 | + end_pos = end; |
3420 | + return result; |
3421 | + } |
3422 | + |
3423 | + public override void set_position (int position) { |
3424 | + textview.set_position (position); |
3425 | + } |
3426 | + |
3427 | + public override void set_size_request (int width, int height) { |
3428 | + textview.set_size_request (width, height); |
3429 | + } |
3430 | + } |
3431 | +} |
3432 | |
3433 | === added file 'src/TextRenderer.vala' |
3434 | --- src/TextRenderer.vala 1970-01-01 00:00:00 +0000 |
3435 | +++ src/TextRenderer.vala 2014-11-22 15:05:49 +0000 |
3436 | @@ -0,0 +1,307 @@ |
3437 | +/* |
3438 | + Copyright (C) 2014 elementary Developers |
3439 | + |
3440 | + This program is free software: you can redistribute it and/or modify it |
3441 | + under the terms of the GNU Lesser General Public License version 3, as published |
3442 | + by the Free Software Foundation. |
3443 | + |
3444 | + This program is distributed in the hope that it will be useful, but |
3445 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
3446 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3447 | + PURPOSE. See the GNU General Public License for more details. |
3448 | + |
3449 | + You should have received a copy of the GNU General Public License along |
3450 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
3451 | + |
3452 | + Authors : Jeremy Wootten <jeremy@elementary.org> |
3453 | +*/ |
3454 | + |
3455 | +namespace Marlin { |
3456 | + public class TextRenderer: Gtk.CellRendererText { |
3457 | + |
3458 | + const int MAX_LINES = 3; |
3459 | + const uint BORDER_RADIUS = 6; |
3460 | + |
3461 | + public Marlin.ZoomLevel zoom_level {get; set;} |
3462 | + public bool follow_state {get; set;} |
3463 | + public new string background { set; private get;} |
3464 | + public GOF.File file {set; private get;} |
3465 | + public int text_width; |
3466 | + public int text_height; |
3467 | + |
3468 | + int char_width; |
3469 | + int char_height; |
3470 | + int focus_border_width; |
3471 | + Pango.Layout layout; |
3472 | + Gtk.Widget widget; |
3473 | + Marlin.AbstractEditableLabel? entry = null; |
3474 | + |
3475 | + public TextRenderer (Marlin.ViewMode viewmode) { |
3476 | + this.mode = Gtk.CellRendererMode.EDITABLE; |
3477 | + |
3478 | + if (viewmode == Marlin.ViewMode.ICON) |
3479 | + entry = new Marlin.MultiLineEditableLabel (); |
3480 | + else |
3481 | + entry = new Marlin.SingleLineEditableLabel (); |
3482 | + |
3483 | + entry.editing_done.connect (on_entry_editing_done); |
3484 | + entry.get_real_editable ().focus_out_event.connect_after (on_entry_focus_out_event); |
3485 | + } |
3486 | + |
3487 | + |
3488 | + public override void render (Cairo.Context cr, |
3489 | + Gtk.Widget widget, |
3490 | + Gdk.Rectangle background_area, |
3491 | + Gdk.Rectangle cell_area, |
3492 | + Gtk.CellRendererState flags) { |
3493 | + set_widget (widget); |
3494 | + Gtk.StateFlags state = widget.get_state_flags (); |
3495 | + |
3496 | + if ((flags & Gtk.CellRendererState.SELECTED) == Gtk.CellRendererState.SELECTED) |
3497 | + state |= Gtk.StateFlags.SELECTED; |
3498 | + else if ((flags & Gtk.CellRendererState.PRELIT) == Gtk.CellRendererState.PRELIT) |
3499 | + state = Gtk.StateFlags.PRELIGHT; |
3500 | + else |
3501 | + state = widget.get_sensitive () ? Gtk.StateFlags.NORMAL : Gtk.StateFlags.INSENSITIVE; |
3502 | + |
3503 | + set_up_layout (text, cell_area); |
3504 | + |
3505 | + var style_context = widget.get_parent ().get_style_context (); |
3506 | + style_context.save (); |
3507 | + style_context.set_state (state); |
3508 | + |
3509 | + if (follow_state || background != null) |
3510 | + draw_focus (cr, cell_area, flags, style_context, state); |
3511 | + |
3512 | + int x_offset, y_offset; |
3513 | + get_offsets (cell_area, text_width, text_height, xalign, out x_offset, out y_offset); |
3514 | + |
3515 | + /* Adjust text offsets for best appearance in each view */ |
3516 | + if (xalign == 0.5f) { /* Icon view */ |
3517 | + x_offset = (cell_area.width - this.wrap_width) / 2; |
3518 | + y_offset += focus_border_width + (int)ypad; |
3519 | + } else { |
3520 | + x_offset += focus_border_width + 2 * (int)xpad; |
3521 | + y_offset += focus_border_width; |
3522 | + } |
3523 | + |
3524 | + style_context.render_layout (cr, |
3525 | + cell_area.x + x_offset, |
3526 | + cell_area.y + y_offset, |
3527 | + layout); |
3528 | + |
3529 | + style_context.restore (); |
3530 | + } |
3531 | + |
3532 | + public void set_up_layout (string? text, Gdk.Rectangle cell_area) { |
3533 | + /* render small/normal text depending on the zoom_level */ |
3534 | + if (text == null) |
3535 | + text= " "; |
3536 | + |
3537 | + bool small = this.zoom_level < Marlin.ZoomLevel.NORMAL; |
3538 | + if (small) |
3539 | + layout.set_attributes (EelPango.attr_list_small ()); |
3540 | + else |
3541 | + layout.set_attributes (null); |
3542 | + |
3543 | + if (wrap_width < 0) { |
3544 | + layout.set_width (cell_area.width * Pango.SCALE); |
3545 | + layout.set_height (- 1); |
3546 | + } else { |
3547 | + layout.set_width (wrap_width * Pango.SCALE); |
3548 | + layout.set_wrap (this.wrap_mode); |
3549 | + layout.set_height (- MAX_LINES); |
3550 | + } |
3551 | + |
3552 | + layout.set_ellipsize (Pango.EllipsizeMode.END); |
3553 | + |
3554 | + if (xalign == 0.5f) |
3555 | + layout.set_alignment (Pango.Alignment.CENTER); |
3556 | + |
3557 | + layout.set_text (text, -1); |
3558 | + |
3559 | + /* calculate the real text dimension */ |
3560 | + int width, height; |
3561 | + layout.get_pixel_size (out width, out height); |
3562 | + text_width = width; |
3563 | + text_height = height; |
3564 | + } |
3565 | + |
3566 | + /* Needs patched gtk+-3.0.vapi file - incorrect function signature up to version 0.25.4 */ |
3567 | + public override unowned Gtk.CellEditable? start_editing (Gdk.Event? event, |
3568 | + Gtk.Widget widget, |
3569 | + string path, |
3570 | + Gdk.Rectangle background_area, |
3571 | + Gdk.Rectangle cell_area, |
3572 | + Gtk.CellRendererState flags) { |
3573 | + |
3574 | + if (!visible || mode != Gtk.CellRendererMode.EDITABLE) |
3575 | + return null; |
3576 | + |
3577 | + float xalign, yalign; |
3578 | + get_alignment (out xalign, out yalign); |
3579 | + |
3580 | + entry.set_text (text); |
3581 | + entry.set_line_wrap (true); |
3582 | + entry.set_line_wrap_mode (wrap_mode); |
3583 | + |
3584 | + if (wrap_width > 0) { /* Icon view */ |
3585 | + entry.set_justify (Gtk.Justification.CENTER); |
3586 | + entry.draw_outline = true; |
3587 | + } else { /*List and Column views */ |
3588 | + entry.set_justify (Gtk.Justification.LEFT); |
3589 | + entry.draw_outline = false; |
3590 | + } |
3591 | + |
3592 | + entry.yalign = this.yalign; |
3593 | + entry.set_padding ((int)xpad, (int)ypad); |
3594 | + entry.set_size_request (wrap_width, -1); |
3595 | + entry.set_position (-1); |
3596 | + entry.set_data ("marlin-text-renderer-path", path.dup ()); |
3597 | + entry.show_all (); |
3598 | + |
3599 | + return entry as Gtk.CellEditable; |
3600 | + } |
3601 | + |
3602 | + private void set_widget (Gtk.Widget? _widget) { |
3603 | + Pango.FontMetrics metrics; |
3604 | + Pango.Context context; |
3605 | + int focus_padding; |
3606 | + int focus_line_width; |
3607 | + |
3608 | + if (_widget == widget) |
3609 | + return; |
3610 | + |
3611 | + /* disconnect from the previously set widget */ |
3612 | + if (widget != null) |
3613 | + disconnect_widget_signals (); |
3614 | + |
3615 | + widget = _widget; |
3616 | + |
3617 | + if (widget != null) { |
3618 | + connect_widget_signals (); |
3619 | + context = widget.get_pango_context (); |
3620 | + layout = new Pango.Layout (context); |
3621 | + layout.set_auto_dir (false); |
3622 | + layout.set_single_paragraph_mode (true); |
3623 | + metrics = context.get_metrics (layout.get_font_description (), context.get_language ()); |
3624 | + char_width = (metrics.get_approximate_char_width () + 512 ) >> 10; |
3625 | + char_height = (metrics.get_ascent () + metrics.get_descent () + 512) >> 10; |
3626 | + if (wrap_width < 0) |
3627 | + (this as Gtk.CellRenderer).set_fixed_size (-1, char_height); |
3628 | + |
3629 | + widget.style_get ("focus-padding", out focus_padding, "focus-line-width", out focus_line_width); |
3630 | + focus_border_width = int.max (focus_padding + focus_line_width, 2); |
3631 | + } else { |
3632 | + layout = null; |
3633 | + char_width = 0; |
3634 | + char_height = 0; |
3635 | + } |
3636 | + } |
3637 | + |
3638 | + private void connect_widget_signals () { |
3639 | + widget.destroy.connect (invalidate); |
3640 | + widget.style_set.connect (invalidate); |
3641 | + } |
3642 | + |
3643 | + private void disconnect_widget_signals () { |
3644 | + widget.destroy.disconnect (invalidate); |
3645 | + widget.style_set.disconnect (invalidate); |
3646 | + } |
3647 | + |
3648 | + private void invalidate () { |
3649 | + set_widget (null); |
3650 | + } |
3651 | + |
3652 | + private void on_entry_editing_done () { |
3653 | + bool cancelled = entry.editing_canceled; |
3654 | + base.stop_editing (cancelled); |
3655 | + |
3656 | + entry.hide (); |
3657 | + |
3658 | + if (!cancelled) { |
3659 | + string text = entry.get_text (); |
3660 | + string path = entry.get_data ("marlin-text-renderer-path"); |
3661 | + edited (path, text); |
3662 | + } |
3663 | + } |
3664 | + |
3665 | + private bool on_entry_focus_out_event (Gdk.Event event) { |
3666 | + on_entry_editing_done (); |
3667 | + return false; |
3668 | + } |
3669 | + |
3670 | + private void draw_focus (Cairo.Context cr, |
3671 | + Gdk.Rectangle cell_area, |
3672 | + Gtk.CellRendererState flags, |
3673 | + Gtk.StyleContext style_context, |
3674 | + Gtk.StateFlags state) { |
3675 | + bool selected = false; |
3676 | + float x; |
3677 | + int x_offset, y_offset, focus_rect_width, focus_rect_height; |
3678 | + |
3679 | + if (follow_state) |
3680 | + selected = ((flags & Gtk.CellRendererState.SELECTED) == Gtk.CellRendererState.SELECTED); |
3681 | + |
3682 | + focus_rect_width = text_width + 4 * this.focus_border_width; |
3683 | + focus_rect_height = text_height + 2 * this.focus_border_width; |
3684 | + |
3685 | + if (widget.get_direction () == Gtk.TextDirection.RTL) |
3686 | + x = 1.0f - xalign; |
3687 | + else |
3688 | + x = xalign; |
3689 | + |
3690 | + get_offsets (cell_area, focus_rect_width, focus_rect_height, x, out x_offset, out y_offset); |
3691 | + |
3692 | + /* render the background if selected or colorized */ |
3693 | + if (selected || this.background != null) { |
3694 | + int x0 = cell_area.x + x_offset + (int)xpad; |
3695 | + int y0 = cell_area.y + y_offset + (int)ypad; |
3696 | + int x1 = x0 + focus_rect_width; |
3697 | + int y1 = y0 + focus_rect_height; |
3698 | + |
3699 | + cr.move_to (x0 + BORDER_RADIUS, y0); |
3700 | + cr.line_to (x1 - BORDER_RADIUS, y0); |
3701 | + cr.curve_to (x1 - BORDER_RADIUS, y0, x1, y0, x1, y0 + BORDER_RADIUS); |
3702 | + cr.line_to (x1, y1 - BORDER_RADIUS); |
3703 | + cr.curve_to (x1, y1 - BORDER_RADIUS, x1, y1, x1 - BORDER_RADIUS, y1); |
3704 | + cr.line_to (x0 + BORDER_RADIUS, y1); |
3705 | + cr.curve_to (x0 + BORDER_RADIUS, y1, x0, y1, x0, y1 - BORDER_RADIUS); |
3706 | + cr.line_to (x0, y0 + BORDER_RADIUS); |
3707 | + cr.curve_to (x0, y0 + BORDER_RADIUS, x0, y0, x0 + BORDER_RADIUS, y0); |
3708 | + |
3709 | + Gdk.RGBA color ={}; |
3710 | + if (background != null && !selected) { |
3711 | + if (!color.parse (background)) { |
3712 | + critical ("Can't parse this color value: %s", background); |
3713 | + color = style_context.get_background_color (state); |
3714 | + } |
3715 | + } else |
3716 | + color = style_context.get_background_color (state); |
3717 | + |
3718 | + Gdk.cairo_set_source_rgba (cr, color); |
3719 | + cr.fill (); |
3720 | + } |
3721 | + /* draw the focus indicator */ |
3722 | + if (follow_state && (flags & Gtk.CellRendererState.FOCUSED) != 0) |
3723 | + style_context.render_focus (cr, |
3724 | + cell_area.x + x_offset, |
3725 | + cell_area.y + y_offset, |
3726 | + focus_rect_width, |
3727 | + focus_rect_height); |
3728 | + } |
3729 | + |
3730 | + private void get_offsets (Gdk.Rectangle cell_area, |
3731 | + int width, |
3732 | + int height, |
3733 | + float x, |
3734 | + out int x_offset, |
3735 | + out int y_offset) { |
3736 | + x_offset = (int)(x * (cell_area.width - width - 2 * (int)xpad)); |
3737 | + x_offset = int.max (x_offset, 0); |
3738 | + |
3739 | + y_offset = (int)(yalign * (cell_area.height - height - 2 * (int)ypad)); |
3740 | + y_offset = int.max (y_offset, 0); |
3741 | + } |
3742 | + } |
3743 | +} |
3744 | |
3745 | === added file 'src/View/AbstractDirectoryView.vala' |
3746 | --- src/View/AbstractDirectoryView.vala 1970-01-01 00:00:00 +0000 |
3747 | +++ src/View/AbstractDirectoryView.vala 2014-11-22 15:05:49 +0000 |
3748 | @@ -0,0 +1,2778 @@ |
3749 | +/* |
3750 | + Copyright (C) 2014 elementary Developers |
3751 | + |
3752 | + This program is free software: you can redistribute it and/or modify it |
3753 | + under the terms of the GNU Lesser General Public License version 3, as published |
3754 | + by the Free Software Foundation. |
3755 | + |
3756 | + This program is distributed in the hope that it will be useful, but |
3757 | + WITHOUT ANY WARRANTY; without even the implied warranties of |
3758 | + MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3759 | + PURPOSE. See the GNU General Public License for more details. |
3760 | + |
3761 | + You should have received a copy of the GNU General Public License along |
3762 | + with this program. If not, see <http://www.gnu.org/licenses/>. |
3763 | + |
3764 | + Authors : Jeremy Wootten <jeremy@elementary.org> |
3765 | +*/ |
3766 | + |
3767 | +/** Implementations of AbstractDirectoryView are |
3768 | + * IconView |
3769 | + * ListView |
3770 | + * ColumnView |
3771 | +**/ |
3772 | + |
3773 | +namespace FM { |
3774 | + public abstract class AbstractDirectoryView : Gtk.ScrolledWindow { |
3775 | + |
3776 | + public enum TargetType { |
3777 | + STRING, |
3778 | + TEXT_URI_LIST, |
3779 | + XDND_DIRECT_SAVE0, |
3780 | + NETSCAPE_URL |
3781 | + } |
3782 | + |
3783 | + protected enum ClickZone { |
3784 | + EXPANDER, |
3785 | + HELPER, |
3786 | + ICON, |
3787 | + NAME, |
3788 | + BLANK_PATH, |
3789 | + BLANK_NO_PATH, |
3790 | + INVALID |
3791 | + } |
3792 | + |
3793 | + const int MAX_TEMPLATES = 32; |
3794 | + |
3795 | + const Gtk.TargetEntry [] drag_targets = { |
3796 | + {"text/plain", 0, TargetType.STRING}, |
3797 | + {"text/uri-list", 0, TargetType.TEXT_URI_LIST} |
3798 | + }; |
3799 | + |
3800 | + const Gtk.TargetEntry [] drop_targets = { |
3801 | + {"text/uri-list", 0, TargetType.TEXT_URI_LIST}, |
3802 | + {"XdndDirectSave0", 0, TargetType.TEXT_URI_LIST}, |
3803 | + {"_NETSCAPE_URL", 0, TargetType.TEXT_URI_LIST} |
3804 | + }; |
3805 | + |
3806 | + const Gdk.DragAction file_drag_actions = (Gdk.DragAction.COPY | Gdk.DragAction.MOVE | Gdk.DragAction.LINK); |
3807 | + |
3808 | + /* Menu Handling */ |
3809 | + const GLib.ActionEntry [] selection_entries = { |
3810 | + {"open", on_selection_action_open_executable}, |
3811 | + {"open_with_app", on_selection_action_open_with_app, "s"}, |
3812 | + {"open_with_default", on_selection_action_open_with_default}, |
3813 | + {"open_with_other_app", on_selection_action_open_with_other_app}, |
3814 | + {"rename", on_selection_action_rename}, |
3815 | + {"cut", on_selection_action_cut}, |
3816 | + {"trash", on_selection_action_trash}, |
3817 | + {"delete", on_selection_action_delete}, |
3818 | + {"restore", on_selection_action_restore} |
3819 | + }; |
3820 | + |
3821 | + const GLib.ActionEntry [] background_entries = { |
3822 | + {"new", on_background_action_new, "s"}, |
3823 | + {"create_from", on_background_action_create_from, "s"}, |
3824 | + {"sort_by", on_background_action_sort_by_changed, "s", "'name'"}, |
3825 | + {"reverse", on_background_action_reverse_changed, null, "false"}, |
3826 | + {"show_hidden", null, null, "false", change_state_show_hidden} |
3827 | + }; |
3828 | + |
3829 | + const GLib.ActionEntry [] common_entries = { |
3830 | + {"copy", on_common_action_copy}, |
3831 | + {"paste_into", on_common_action_paste_into}, |
3832 | + {"open_in", on_common_action_open_in, "s"}, |
3833 | + {"bookmark", on_common_action_bookmark}, |
3834 | + {"properties", on_common_action_properties} |
3835 | + }; |
3836 | + |
3837 | + GLib.SimpleActionGroup common_actions; |
3838 | + GLib.SimpleActionGroup selection_actions; |
3839 | + GLib.SimpleActionGroup background_actions; |
3840 | + |
3841 | + private Marlin.ZoomLevel _zoom_level; |
3842 | + public Marlin.ZoomLevel zoom_level { |
3843 | + get { |
3844 | + return _zoom_level; |
3845 | + } |
3846 | + |
3847 | + set { |
3848 | + if (value <= maximum_zoom && |
3849 | + value >= minimum_zoom && |
3850 | + value != _zoom_level) { |
3851 | + |
3852 | + _zoom_level = value; |
3853 | + on_zoom_level_changed (value); |
3854 | + } |
3855 | + } |
3856 | + } |
3857 | + |
3858 | + public int icon_size { |
3859 | + get { |
3860 | + return Marlin.zoom_level_to_icon_size (_zoom_level); |
3861 | + } |
3862 | + } |
3863 | + |
3864 | + protected Marlin.ZoomLevel minimum_zoom = Marlin.ZoomLevel.SMALLEST; |
3865 | + protected Marlin.ZoomLevel maximum_zoom = Marlin.ZoomLevel.LARGEST; |
3866 | + |
3867 | + /* drag support */ |
3868 | + uint drag_scroll_timer_id = 0; |
3869 | + uint drag_timer_id = 0; |
3870 | + int drag_x = 0; |
3871 | + int drag_y = 0; |
3872 | + int drag_button; |
3873 | + protected int drag_delay = Gtk.Settings.get_default ().gtk_menu_popup_delay; |
3874 | + |
3875 | + Gdk.DragAction current_suggested_action = Gdk.DragAction.DEFAULT; |
3876 | + Gdk.DragAction current_actions = Gdk.DragAction.DEFAULT; |
3877 | + |
3878 | + unowned GLib.List<unowned GOF.File> drag_file_list = null; |
3879 | + GOF.File? drop_target_file = null; |
3880 | + |
3881 | + |
3882 | + /* drop site support */ |
3883 | + bool _drop_highlight; |
3884 | + bool drop_highlight { |
3885 | + get { |
3886 | + return _drop_highlight; |
3887 | + } |
3888 | + |
3889 | + set { |
3890 | + if (value != _drop_highlight) { |
3891 | + if (value) |
3892 | + Gtk.drag_highlight (this); |
3893 | + else |
3894 | + Gtk.drag_unhighlight (this); |
3895 | + } |
3896 | + _drop_highlight = value; |
3897 | + } |
3898 | + } |
3899 | + |
3900 | + private bool drop_data_ready = false; /* whether the drop data was received already */ |
3901 | + private bool drop_occurred = false; /* whether the data was dropped */ |
3902 | + private bool drag_has_begun = false; |
3903 | + protected bool dnd_disabled = false; |
3904 | + private void* drag_data; |
3905 | + private GLib.List<GLib.File> drop_file_list = null; /* the list of URIs that are contained in the drop data */ |
3906 | + |
3907 | + /* support for generating thumbnails */ |
3908 | + uint thumbnail_request = 0; |
3909 | + uint thumbnail_source_id = 0; |
3910 | + Marlin.Thumbnailer thumbnailer = null; |
3911 | + |
3912 | + /* TODO Support for preview see bug #1380139 */ |
3913 | + private string? previewer = null; |
3914 | + |
3915 | + /* Rename support */ |
3916 | + protected Gtk.TreeViewColumn name_column; |
3917 | + protected Marlin.TextRenderer? name_renderer = null; |
3918 | + unowned Marlin.AbstractEditableLabel? editable_widget = null; |
3919 | + public string original_name = ""; |
3920 | + |
3921 | + /* Support for zoom by smooth scrolling */ |
3922 | + private double total_delta_y = 0.0; |
3923 | + |
3924 | + /* UI options for button press handling */ |
3925 | + protected bool single_click_rename = false; |
3926 | + protected bool activate_on_blank = true; |
3927 | + protected bool right_margin_unselects_all = false; |
3928 | + public bool single_click_mode {get; set;} |
3929 | + protected bool should_activate = false; |
3930 | + protected bool should_scroll = true; |
3931 | + protected uint click_zone = ClickZone.ICON; |
3932 | + protected uint previous_click_zone = ClickZone.ICON; |
3933 | + |
3934 | + /* Cursors for different areas */ |
3935 | + private Gdk.Cursor editable_cursor; |
3936 | + private Gdk.Cursor activatable_cursor; |
3937 | + private Gdk.Cursor blank_cursor; |
3938 | + private Gdk.Cursor selectable_cursor; |
3939 | + |
3940 | + private GLib.List<GLib.AppInfo> open_with_apps; |
3941 | + protected GLib.List<GOF.Directory.Async>? loaded_subdirectories = null; |
3942 | + protected GLib.List<unowned GOF.File> selected_files = null ; |
3943 | + private GLib.List<unowned GOF.File>? templates = null; |
3944 | + |
3945 | + private GLib.AppInfo default_app; |
3946 | + private Gtk.TreePath selection_before_delete; |
3947 | + private Gtk.TreePath? hover_path = null; |
3948 | + |
3949 | + private bool selection_was_removed = false; |
3950 | + public bool select_added_files = false; |
3951 | + protected bool renaming = false; |
3952 | + private bool updates_frozen = false; |
3953 | + protected bool tree_frozen = false; |
3954 | + private bool in_trash = false; |
3955 | + protected bool is_loading; |
3956 | + protected bool helpers_shown; |
3957 | + private uint select_timeout_id = 0; |
3958 | + |
3959 | + private Gtk.Widget view; |
3960 | + private unowned Marlin.ClipboardManager clipboard; |
3961 | + protected FM.ListModel model; |
3962 | + protected Marlin.IconRenderer icon_renderer; |
3963 | + protected unowned Marlin.View.Slot slot; |
3964 | + protected unowned Marlin.View.Window window; /*For convenience - this can be derived from slot */ |
3965 | + protected static DndHandler dnd_handler = new FM.DndHandler (); |
3966 | + |
3967 | + public signal void path_change_request (GLib.File location, int flag = 0, bool new_root = true); |
3968 | + |
3969 | + |
3970 | + public AbstractDirectoryView (Marlin.View.Slot _slot) { |
3971 | + slot = _slot; |
3972 | + window = _slot.window; |
3973 | + editable_cursor = new Gdk.Cursor (Gdk.CursorType.XTERM); |
3974 | + activatable_cursor = new Gdk.Cursor (Gdk.CursorType.HAND1); |
3975 | + selectable_cursor = new Gdk.Cursor (Gdk.CursorType.ARROW); |
3976 | + blank_cursor = new Gdk.Cursor (Gdk.CursorType.CROSSHAIR); |
3977 | + clipboard = ((Marlin.Application)(window.application)).get_clipboard_manager (); |
3978 | + icon_renderer = new Marlin.IconRenderer (); |
3979 | + thumbnailer = Marlin.Thumbnailer.get (); |
3980 | + model = GLib.Object.@new (FM.ListModel.get_type (), null) as FM.ListModel; |
3981 | + Preferences.settings.bind ("single-click", this, "single_click_mode", SettingsBindFlags.GET); |
3982 | + |
3983 | + /* Currently, "single-click rename" is disabled, matching existing UI |
3984 | + * Currently, "activate on blank" is enabled, matching existing UI |
3985 | + * Currently, "right margin unselects all" is disabled, matching existing UI |
3986 | + */ |
3987 | + |
3988 | + set_up__menu_actions (); |
3989 | + set_up_directory_view (); |
3990 | + view = create_view (); |
3991 | + |
3992 | + if (view != null) { |
3993 | + add (view); |
3994 | + show_all (); |
3995 | + connect_drag_drop_signals (view); |
3996 | + view.add_events (Gdk.EventMask.POINTER_MOTION_MASK); |
3997 | + view.motion_notify_event.connect (on_motion_notify_event); |
3998 | + view.leave_notify_event.connect (on_leave_notify_event); |
3999 | + view.enter_notify_event.connect (on_enter_notify_event); |
4000 | + view.key_press_event.connect (on_view_key_press_event); |
4001 | + view.button_press_event.connect (on_view_button_press_event); |
4002 | + view.button_release_event.connect (on_view_button_release_event); |
4003 | + view.draw.connect (on_view_draw); |
4004 | + } |
4005 | + |
4006 | + freeze_tree (); /* speed up loading of icon view. Thawed when directory loaded */ |
4007 | + set_up_zoom_level (); |
4008 | + change_zoom_level (); |
4009 | + } |
4010 | + |
4011 | + ~AbstractDirectoryView () { |
4012 | + loaded_subdirectories.@foreach ((dir) => { |
4013 | + remove_subdirectory (dir); |
4014 | + }); |
4015 | + } |
4016 | + |
4017 | + protected virtual void set_up_name_renderer () { |
4018 | + name_renderer.editable = false; |
4019 | + name_renderer.follow_state = true; |
4020 | + name_renderer.edited.connect (on_name_edited); |
4021 | + name_renderer.editing_canceled.connect (on_name_editing_canceled); |
4022 | + name_renderer.editing_started.connect (on_name_editing_started); |
4023 | + } |
4024 | + |
4025 | + private void set_up_directory_view () { |
4026 | + set_policy (Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC); |
4027 | + set_shadow_type (Gtk.ShadowType.NONE); |
4028 | + |
4029 | + size_allocate.connect_after (on_size_allocate); |
4030 | + button_press_event.connect (on_button_press_event); |
4031 | + popup_menu.connect (on_popup_menu); |
4032 | + |
4033 | + unrealize.connect (() => { |
4034 | + clipboard.changed.disconnect (on_clipboard_changed); |
4035 | + }); |
4036 | + |
4037 | + realize.connect (() => { |
4038 | + clipboard.changed.connect (on_clipboard_changed); |
4039 | + on_clipboard_changed (); |
4040 | + }); |
4041 | + |
4042 | + scroll_event.connect (on_scroll_event); |
4043 | + |
4044 | + get_vadjustment ().value_changed.connect ((alloc) => { |
4045 | + schedule_thumbnail_timeout (); |
4046 | + }); |
4047 | + |
4048 | + (GOF.Preferences.get_default ()).notify["show-hidden-files"].connect (on_show_hidden_files_changed); |
4049 | + (GOF.Preferences.get_default ()).notify["interpret-desktop-files"].connect (on_interpret_desktop_files_changed); |
4050 | + |
4051 | + connect_directory_handlers (slot.directory); |
4052 | + |
4053 | + model.row_deleted.connect (on_row_deleted); |
4054 | + model.row_deleted.connect_after (after_restore_selection); |
4055 | + |
4056 | + model.sort_column_changed.connect (on_sort_column_changed); |
4057 | + model.set_sort_column_id (slot.directory.file.sort_column_id, slot.directory.file.sort_order); |
4058 | + |
4059 | + } |
4060 | + |
4061 | + private void set_up__menu_actions () { |
4062 | + selection_actions = new GLib.SimpleActionGroup (); |
4063 | + selection_actions.add_action_entries (selection_entries, this); |
4064 | + insert_action_group ("selection", selection_actions); |
4065 | + |
4066 | + background_actions = new GLib.SimpleActionGroup (); |
4067 | + background_actions.add_action_entries (background_entries, this); |
4068 | + insert_action_group ("background", background_actions); |
4069 | + |
4070 | + common_actions = new GLib.SimpleActionGroup (); |
4071 | + common_actions.add_action_entries (common_entries, this); |
4072 | + insert_action_group ("common", common_actions); |
4073 | + |
4074 | + action_set_state (background_actions, "show_hidden", Preferences.settings.get_boolean ("show-hiddenfiles")); |
4075 | + } |
4076 | + |
4077 | + public void zoom_in () { |
4078 | + zoom_level = zoom_level + 1; |
4079 | + } |
4080 | + |
4081 | + public void zoom_out () { |
4082 | + zoom_level = zoom_level - 1; |
4083 | + } |
4084 | + |
4085 | + private void set_up_zoom_level () { |
4086 | + zoom_level = get_set_up_zoom_level (); |
4087 | + model.set_property ("size", icon_size); |
4088 | + } |
4089 | + |
4090 | + public void zoom_normal () { |
4091 | + zoom_level = get_normal_zoom_level (); |
4092 | + } |
4093 | + |
4094 | + public void select_first_for_empty_selection () { |
4095 | + if (selected_files == null) |
4096 | + set_cursor (new Gtk.TreePath.from_indices (0), false, true, true); |
4097 | + } |
4098 | + |
4099 | + public void select_glib_files (GLib.List<GLib.File> location_list, GLib.File? focus_location) { |
4100 | + updates_frozen = true; |
4101 | + unselect_all (); |
4102 | + GLib.List<GOF.File>? file_list = null; |
4103 | + |
4104 | + if (focus_location == null) |
4105 | + focus_location = location_list.first ().data; |
4106 | + |
4107 | + location_list.@foreach ((loc) => { |
4108 | + file_list.prepend (GOF.File.@get (loc)); |
4109 | + }); |
4110 | + |
4111 | + /* Because the Icon View disconnects the model while loading, we need to wait until |
4112 | + * the tree is thawed and the model reconnected before selecting the files */ |
4113 | + select_timeout_id = GLib.Timeout.add (100, () => { |
4114 | + if (tree_frozen) |
4115 | + return true; |
4116 | + |
4117 | + file_list.@foreach ((file) => { |
4118 | + var iter = Gtk.TreeIter (); |
4119 | + |
4120 | + if (model.get_first_iter_for_file (file, out iter)) { |
4121 | + Gtk.TreePath path = model.get_path (iter); |
4122 | + if (path != null) { |
4123 | + if (focus_location == file.location) |
4124 | + set_cursor (path, false, true, false); /* set cursor and select */ |
4125 | + else |
4126 | + select_path (path); |
4127 | + } |
4128 | + } |
4129 | + }); |
4130 | + select_timeout_id = 0; |
4131 | + return false; |
4132 | + }); |
4133 | + |
4134 | + updates_frozen = false; |
4135 | + update_selected_files (); |
4136 | + notify_selection_changed (); |
4137 | + grab_focus (); |
4138 | + } |
4139 | + |
4140 | + public unowned GLib.List<GLib.AppInfo> get_open_with_apps () { |
4141 | + return open_with_apps; |
4142 | + } |
4143 | + |
4144 | + public unowned GLib.AppInfo get_default_app () { |
4145 | + return default_app; |
4146 | + } |
4147 | + |
4148 | + public void set_updates_frozen (bool freeze) { |
4149 | + if (freeze && !updates_frozen) |
4150 | + freeze_updates (); |
4151 | + else if (!freeze && updates_frozen) |
4152 | + unfreeze_updates (); |
4153 | + } |
4154 | + |
4155 | + public bool get_updates_frozen () { |
4156 | + return updates_frozen; |
4157 | + } |
4158 | + |
4159 | + protected void freeze_updates () { |
4160 | + updates_frozen = true; |
4161 | + slot.directory.freeze_update = true; |
4162 | + action_set_enabled (selection_actions, "cut", false); |
4163 | + action_set_enabled (common_actions, "copy", false); |
4164 | + action_set_enabled (common_actions, "paste_into", false); |
4165 | + action_set_enabled (window.win_actions, "select_all", false); |
4166 | + |
4167 | + size_allocate.disconnect (on_size_allocate); |
4168 | + clipboard.changed.disconnect (on_clipboard_changed); |
4169 | + view.enter_notify_event.disconnect (on_enter_notify_event); |
4170 | + view.key_press_event.disconnect (on_view_key_press_event); |
4171 | + } |
4172 | + |
4173 | + protected void unfreeze_updates () { |
4174 | + updates_frozen = false; |
4175 | + slot.directory.freeze_update = false;; |
4176 | + update_menu_actions (); |
4177 | + size_allocate.connect (on_size_allocate); |
4178 | + clipboard.changed.connect (on_clipboard_changed); |
4179 | + view.enter_notify_event.connect (on_enter_notify_event); |
4180 | + view.key_press_event.connect (on_view_key_press_event); |
4181 | + } |
4182 | + |
4183 | + public new void grab_focus () { |
4184 | + if (view.get_realized ()) |
4185 | + view.grab_focus (); |
4186 | + else { /* wait until realized */ |
4187 | + GLib.Timeout.add (100, () => { |
4188 | + view.grab_focus (); |
4189 | + return !view.get_realized (); |
4190 | + }); |
4191 | + } |
4192 | + } |
4193 | + |
4194 | + public unowned GLib.List<unowned GOF.File> get_selected_files () { |
4195 | + return selected_files; |
4196 | + } |
4197 | + |
4198 | + public bool is_frozen () { |
4199 | + return updates_frozen; |
4200 | + } |
4201 | + |
4202 | +/*** Protected Methods */ |
4203 | + protected void set_active_slot (bool scroll = true) { |
4204 | + slot.active (scroll); |
4205 | + } |
4206 | + |
4207 | + protected void load_location (GLib.File location) { |
4208 | + path_change_request (location, Marlin.OpenFlag.DEFAULT, false); |
4209 | + } |
4210 | + |
4211 | + protected void load_root_location (GLib.File location) { |
4212 | + path_change_request (location, Marlin.OpenFlag.DEFAULT, true); |
4213 | + } |
4214 | + |
4215 | + /** Operations on selections */ |
4216 | + protected void activate_selected_items (Marlin.OpenFlag flag = Marlin.OpenFlag.DEFAULT, |
4217 | + GLib.List<unowned GOF.File> selection = get_selected_files ()) { |
4218 | + if (updates_frozen || in_trash) |
4219 | + return; |
4220 | + |
4221 | + uint nb_elem = selection.length (); |
4222 | + |
4223 | + if (nb_elem < 1) |
4224 | + return; |
4225 | + |
4226 | + unowned Gdk.Screen screen = Eel.gtk_widget_get_screen (this); |
4227 | + bool only_folders = selection_only_contains_folders (selection); |
4228 | + |
4229 | + if (nb_elem < 10 && (default_app == null || only_folders)) { |
4230 | + /* launch each selected file individually ignoring selections greater than 10 */ |
4231 | + bool only_one_file = (nb_elem == 1); |
4232 | + |
4233 | + foreach (unowned GOF.File file in selection) { |
4234 | + /* Prevent too rapid activation of files - causes New Tab to crash for example */ |
4235 | + GLib.Timeout.add (50, () => { |
4236 | + activate_file (file, screen, flag, only_one_file); |
4237 | + return false; |
4238 | + }); |
4239 | + } |
4240 | + } else if (default_app != null) |
4241 | + open_files_with (default_app, selection); |
4242 | + } |
4243 | + |
4244 | + protected void preview_selected_items () { |
4245 | + if (previewer == null) /* At present this is the case! */ |
4246 | + activate_selected_items (Marlin.OpenFlag.DEFAULT); |
4247 | + else { |
4248 | + unowned GLib.List<unowned GOF.File>? selection = get_selected_files (); |
4249 | + |
4250 | + if (selection == null) |
4251 | + return; |
4252 | + |
4253 | + Gdk.Screen screen = Eel.gtk_widget_get_screen (this); |
4254 | + GLib.List<GLib.File> location_list = null; |
4255 | + GOF.File file = selection.data; |
4256 | + location_list.prepend (file.location); |
4257 | + Gdk.AppLaunchContext context = screen.get_display ().get_app_launch_context (); |
4258 | + try { |
4259 | + GLib.AppInfo previewer_app = GLib.AppInfo.create_from_commandline (previewer, null, 0); |
4260 | + previewer_app.launch (location_list, context as GLib.AppLaunchContext); |
4261 | + } catch (GLib.Error error) { |
4262 | + Eel.show_error_dialog (_("Failed to preview"), error.message, null); |
4263 | + } |
4264 | + } |
4265 | + } |
4266 | + |
4267 | + protected void select_gof_file (GOF.File file) { |
4268 | + var iter = Gtk.TreeIter (); |
4269 | + |
4270 | + if (!model.get_first_iter_for_file (file, out iter)) |
4271 | + return; /* file not in model */ |
4272 | + |
4273 | + var path = model.get_path (iter); |
4274 | + set_cursor (path, false, true, false); |
4275 | + } |
4276 | + |
4277 | + protected void add_gof_file_to_selection (GOF.File file) { |
4278 | + var iter = Gtk.TreeIter (); |
4279 | + |
4280 | + if (!model.get_first_iter_for_file (file, out iter)) |
4281 | + return; /* file not in model */ |
4282 | + |
4283 | + var path = model.get_path (iter); |
4284 | + select_path (path); |
4285 | + } |
4286 | + |
4287 | + protected void after_restore_selection (Gtk.TreePath path) { |
4288 | + set_cursor (selection_before_delete, false, true, false); |
4289 | + selection_before_delete = null; |
4290 | + } |
4291 | + |
4292 | + /** Directory signal handlers. */ |
4293 | + /* Signal could be from subdirectory as well as slot directory */ |
4294 | + protected void connect_directory_handlers (GOF.Directory.Async dir) { |
4295 | + assert (dir != null); |
4296 | + dir.file_loaded.connect (on_directory_file_loaded); |
4297 | + dir.file_added.connect (on_directory_file_added); |
4298 | + dir.file_changed.connect (on_directory_file_changed); |
4299 | + dir.file_deleted.connect (on_directory_file_deleted); |
4300 | + dir.icon_changed.connect (on_directory_file_icon_changed); |
4301 | + dir.done_loading.connect (on_directory_done_loading); |
4302 | + dir.thumbs_loaded.connect (on_directory_thumbs_loaded); |
4303 | + } |
4304 | + |
4305 | + protected void disconnect_directory_handlers (GOF.Directory.Async dir) { |
4306 | + /* If the directory is still loading the file_loaded signal handler |
4307 | + /* will not have been disconnected */ |
4308 | + if (dir.is_loading ()) |
4309 | + dir.file_loaded.disconnect (on_directory_file_loaded); |
4310 | + |
4311 | + dir.file_added.disconnect (on_directory_file_added); |
4312 | + dir.file_changed.disconnect (on_directory_file_changed); |
4313 | + dir.file_deleted.disconnect (on_directory_file_deleted); |
4314 | + dir.icon_changed.disconnect (on_directory_file_icon_changed); |
4315 | + dir.done_loading.disconnect (on_directory_done_loading); |
4316 | + dir.thumbs_loaded.disconnect (on_directory_thumbs_loaded); |
4317 | + } |
4318 | + |
4319 | + public void change_directory (GOF.Directory.Async old_dir, GOF.Directory.Async new_dir) { |
4320 | + cancel_thumbnailing (); |
4321 | + freeze_tree (); |
4322 | + old_dir.cancel (); |
4323 | + disconnect_directory_handlers (old_dir); |
4324 | + block_model (); |
4325 | + |
4326 | + loaded_subdirectories.@foreach ((dir) => { |
4327 | + remove_subdirectory (dir); |
4328 | + }); |
4329 | + |
4330 | + loaded_subdirectories = null; |
4331 | + model.clear (); |
4332 | + unblock_model (); |
4333 | + |
4334 | + connect_directory_handlers (new_dir); |
4335 | + update_menu_actions (); |
4336 | + model.set_sort_column_id (slot.directory.file.sort_column_id, slot.directory.file.sort_order); |
4337 | + } |
4338 | + |
4339 | + public void reload () { |
4340 | + change_directory (slot.directory, slot.directory); |
4341 | + } |
4342 | + |
4343 | + protected void connect_drag_drop_signals (Gtk.Widget widget) { |
4344 | + /* Set up as drop site */ |
4345 | + Gtk.drag_dest_set (widget, Gtk.DestDefaults.MOTION, drop_targets, Gdk.DragAction.ASK | file_drag_actions); |
4346 | + widget.drag_drop.connect (on_drag_drop); |
4347 | + widget.drag_data_received.connect (on_drag_data_received); |
4348 | + widget.drag_leave.connect (on_drag_leave); |
4349 | + widget.drag_motion.connect (on_drag_motion); |
4350 | + |
4351 | + /* Set up as drag source */ |
4352 | + Gtk.drag_source_set (widget, Gdk.ModifierType.BUTTON1_MASK, drag_targets, file_drag_actions); |
4353 | + widget.drag_begin.connect (on_drag_begin); |
4354 | + widget.drag_data_get.connect (on_drag_data_get); |
4355 | + widget.drag_data_delete.connect (on_drag_data_delete); |
4356 | + widget.drag_end.connect (on_drag_end); |
4357 | + } |
4358 | + |
4359 | + protected void cancel_drag_timer () { |
4360 | + disconnect_drag_timeout_motion_and_release_events (); |
4361 | + cancel_timeout (ref drag_timer_id); |
4362 | + } |
4363 | + |
4364 | + protected void cancel_thumbnailing () { |
4365 | + slot.directory.cancel (); |
4366 | + cancel_timeout (ref thumbnail_source_id); |
4367 | + |
4368 | + if (thumbnail_request > 0) { |
4369 | + thumbnailer.dequeue (thumbnail_request); |
4370 | + thumbnail_request = 0; |
4371 | + } |
4372 | + } |
4373 | + |
4374 | + protected bool is_drag_pending () { |
4375 | + return drag_has_begun; |
4376 | + } |
4377 | + |
4378 | + protected bool selection_only_contains_folders (GLib.List<unowned GOF.File> list) { |
4379 | + bool only_folders = true; |
4380 | + |
4381 | + list.@foreach ((file) => { |
4382 | + if (!file.is_folder ()) |
4383 | + only_folders = false; |
4384 | + }); |
4385 | + |
4386 | + return only_folders; |
4387 | + } |
4388 | + |
4389 | + /** Handle scroll events */ |
4390 | + protected bool handle_scroll_event (Gdk.EventScroll event) { |
4391 | + if (updates_frozen) |
4392 | + return true; |
4393 | + |
4394 | + if ((event.state & Gdk.ModifierType.CONTROL_MASK) > 0) { |
4395 | + switch (event.direction) { |
4396 | + case Gdk.ScrollDirection.UP: |
4397 | + zoom_in (); |
4398 | + return true; |
4399 | + |
4400 | + case Gdk.ScrollDirection.DOWN: |
4401 | + zoom_out (); |
4402 | + return true; |
4403 | + |
4404 | + case Gdk.ScrollDirection.SMOOTH: |
4405 | + double delta_x, delta_y; |
4406 | + event.get_scroll_deltas (out delta_x, out delta_y); |
4407 | + /* try to emulate a normal scrolling event by summing deltas. |
4408 | + * step size of 0.5 chosen to match sensitivity */ |
4409 | + total_delta_y += delta_y; |
4410 | + |
4411 | + if (total_delta_y >= 0.5) { |
4412 | + total_delta_y = 0; |
4413 | + zoom_out (); |
4414 | + } else if (total_delta_y <= -0.5) { |
4415 | + total_delta_y = 0; |
4416 | + zoom_in (); |
4417 | + } |
4418 | + return true; |
4419 | + |
4420 | + default: |
4421 | + break; |
4422 | + } |
4423 | + } |
4424 | + return false; |
4425 | + } |
4426 | + |
4427 | + protected void show_or_queue_context_menu (Gdk.Event event) { |
4428 | + if (selected_files != null) |
4429 | + queue_context_menu (event); |
4430 | + else |
4431 | + show_context_menu (event); |
4432 | + } |
4433 | + |
4434 | + protected unowned GLib.List<unowned GOF.File> get_selected_files_for_transfer (GLib.List<unowned GOF.File> selection = get_selected_files ()) { |
4435 | + unowned GLib.List<unowned GOF.File> list = null; |
4436 | + |
4437 | + selection.@foreach ((file) => { |
4438 | + list.prepend (file); |
4439 | + }); |
4440 | + |
4441 | + return list; |
4442 | + } |
4443 | + |
4444 | +/*** Private methods */ |
4445 | + /** File operations */ |
4446 | + |
4447 | + private void activate_file (GOF.File file, Gdk.Screen? screen, Marlin.OpenFlag flag, bool only_one_file) { |
4448 | + if (updates_frozen || in_trash) |
4449 | + return; |
4450 | + |
4451 | + debug ("activate file %s only one file %s", file.uri, only_one_file.to_string ()); |
4452 | + GLib.File location = file.location.dup (); |
4453 | + |
4454 | + if (screen == null) |
4455 | + screen = Eel.gtk_widget_get_screen (this); |
4456 | + |
4457 | + if (file.is_folder ()) { |
4458 | + switch (flag) { |
4459 | + case Marlin.OpenFlag.NEW_TAB: |
4460 | + window.add_tab (location, Marlin.ViewMode.CURRENT); |
4461 | + break; |
4462 | + |
4463 | + case Marlin.OpenFlag.NEW_WINDOW: |
4464 | + window.add_window(location, Marlin.ViewMode.CURRENT); |
4465 | + break; |
4466 | + |
4467 | + default: |
4468 | + if (only_one_file) |
4469 | + load_location (location); |
4470 | + |
4471 | + break; |
4472 | + } |
4473 | + } else if (only_one_file && file.is_root_network_folder ()) |
4474 | + load_location (location); |
4475 | + else if (only_one_file && file.is_executable ()) |
4476 | + file.execute (screen, null, null); |
4477 | + else if (only_one_file && default_app != null) |
4478 | + file.open_single (screen, default_app); |
4479 | + else |
4480 | + warning ("Unable to activate this file. Default app is %s", default_app != null ? default_app.get_name () : "null"); |
4481 | + } |
4482 | + |
4483 | + private void trash_or_delete_files (GLib.List<unowned GOF.File> file_list, bool delete_if_already_in_trash) { |
4484 | + GLib.List<GLib.File> locations = null; |
4485 | + |
4486 | + file_list.@foreach ((file) => { |
4487 | + locations.prepend (file.location); |
4488 | + }); |
4489 | + |
4490 | + if (locations != null) { |
4491 | + locations.reverse (); |
4492 | + Marlin.FileOperations.trash_or_delete (locations, |
4493 | + window as Gtk.Window, |
4494 | + (void*) after_trash_or_delete, |
4495 | + null); |
4496 | + } |
4497 | + } |
4498 | + |
4499 | + private void add_file (GOF.File file, GOF.Directory.Async dir) { |
4500 | + model.add_file (file, dir); |
4501 | + |
4502 | + if (select_added_files) |
4503 | + add_gof_file_to_selection (file); |
4504 | + } |
4505 | + |
4506 | + private void new_empty_file (string? parent_uri = null) { |
4507 | + if (parent_uri == null) |
4508 | + parent_uri = slot.directory.file.uri; |
4509 | + |
4510 | + Marlin.FileOperations.new_file (this as Gtk.Widget, |
4511 | + null, |
4512 | + parent_uri, |
4513 | + null, |
4514 | + null, |
4515 | + 0, |
4516 | + (Marlin.CreateCallback?) create_file_done, |
4517 | + this); |
4518 | + } |
4519 | + |
4520 | + private void new_empty_folder () { |
4521 | + Marlin.FileOperations.new_folder (null, null, slot.location, (Marlin.CreateCallback?) create_file_done, this); |
4522 | + } |
4523 | + |
4524 | + protected void rename_file (GOF.File file_to_rename) { |
4525 | + unselect_all (); |
4526 | + select_gof_file (file_to_rename); |
4527 | + |
4528 | + if (file_to_rename.is_writable ()) |
4529 | + start_renaming_file (file_to_rename, false); |
4530 | + else |
4531 | + warning ("You do not have permission to rename this file"); |
4532 | + } |
4533 | + |
4534 | + |
4535 | +/** File operation callbacks */ |
4536 | + static void create_file_done (GLib.File? new_file, void* data) { |
4537 | + if (new_file == null) |
4538 | + return; |
4539 | + |
4540 | + var view = (FM.AbstractDirectoryView)data; |
4541 | + var file_to_rename = GOF.File.@get (new_file); |
4542 | + /* Allow time for the file to appear in the tree model before renaming */ |
4543 | + GLib.Timeout.add (50, () => { |
4544 | + view.rename_file (file_to_rename); |
4545 | + return false; |
4546 | + }); |
4547 | + } |
4548 | + |
4549 | + private void after_trash_or_delete (GLib.HashTable? debuting_files, bool user_cancel, void* data) { |
4550 | + if (user_cancel) |
4551 | + selection_was_removed = false; |
4552 | + } |
4553 | + |
4554 | + private void trash_or_delete_selected_files () { |
4555 | + /* This might be rapidly called multiple times for the same selection |
4556 | + * when using keybindings. So we remember if the current selection |
4557 | + * was already removed (but the view doesn't know about it yet). |
4558 | + */ |
4559 | + if (!selection_was_removed) { |
4560 | + unowned GLib.List<unowned GOF.File> selection = get_selected_files_for_transfer (); |
4561 | + if (selection != null) { |
4562 | + selection_was_removed = true; |
4563 | + trash_or_delete_files (selection, true); |
4564 | + } |
4565 | + } |
4566 | + } |
4567 | + |
4568 | + |
4569 | + private void delete_selected_files () { |
4570 | + unowned GLib.List<unowned GOF.File> selection = get_selected_files_for_transfer (); |
4571 | + if (selection == null) |
4572 | + return; |
4573 | + |
4574 | + GLib.List<GLib.File> locations = null; |
4575 | + |
4576 | + selection.@foreach ((file) => { |
4577 | + locations.prepend (file.location); |
4578 | + }); |
4579 | + |
4580 | + locations.reverse (); |
4581 | + Marlin.FileOperations.@delete (locations, window as Gtk.Window, null, null); |
4582 | + } |
4583 | + |
4584 | +/** Signal Handlers */ |
4585 | + |
4586 | + /** Menu actions */ |
4587 | + /** Selection actions */ |
4588 | + |
4589 | + private void on_selection_action_rename (GLib.SimpleAction action, GLib.Variant? param) { |
4590 | + rename_selected_file (); |
4591 | + } |
4592 | + |
4593 | + private void rename_selected_file () { |
4594 | + if (selected_files == null) |
4595 | + return; |
4596 | + |
4597 | + if (selected_files.next != null) |
4598 | + /* TODO invoke batch renamer see bug #1014122*/ |
4599 | + warning ("Cannot rename multiple files (yet) - renaming first only"); |
4600 | + |
4601 | + var file = selected_files.first ().data; |
4602 | + bool preselect_whole_name = file.is_folder (); |
4603 | + |
4604 | + start_renaming_file (file, preselect_whole_name); |
4605 | + } |
4606 | + |
4607 | + private void on_selection_action_cut (GLib.SimpleAction action, GLib.Variant? param) { |
4608 | + unowned GLib.List<unowned GOF.File> selection = get_selected_files_for_transfer (); |
4609 | + clipboard.cut_files (selection); |
4610 | + } |
4611 | + |
4612 | + private void on_selection_action_trash (GLib.SimpleAction action, GLib.Variant? param) { |
4613 | + trash_or_delete_selected_files (); |
4614 | + } |
4615 | + |
4616 | + private void on_selection_action_delete (GLib.SimpleAction action, GLib.Variant? param) { |
4617 | + delete_selected_files (); |
4618 | + } |
4619 | + |
4620 | + private void on_selection_action_restore (GLib.SimpleAction action, GLib.Variant? param) { |
4621 | + unowned GLib.List<unowned GOF.File> selection = get_selected_files_for_transfer (); |
4622 | + Marlin.restore_files_from_trash (selection, window); |
4623 | + } |
4624 | + |
4625 | + private void on_selection_action_open_executable (GLib.SimpleAction action, GLib.Variant? param) { |
4626 | + unowned GLib.List<unowned GOF.File> selection = get_files_for_action (); |
4627 | + GOF.File file = selection.data as GOF.File; |
4628 | + unowned Gdk.Screen screen = Eel.gtk_widget_get_screen (this); |
4629 | + file.execute (screen, null, null); |
4630 | + } |
4631 | + |
4632 | + private void on_selection_action_open_with_default (GLib.SimpleAction action, GLib.Variant? param) { |
4633 | + activate_selected_items (Marlin.OpenFlag.DEFAULT); |
4634 | + } |
4635 | + |
4636 | + private void on_selection_action_open_with_app (GLib.SimpleAction action, GLib.Variant? param) { |
4637 | + var index = int.parse (param.get_string ()); |
4638 | + open_files_with (open_with_apps.nth_data ((uint)index), get_files_for_action ()); |
4639 | + } |
4640 | + |
4641 | + private void on_selection_action_open_with_other_app () { |
4642 | + unowned GLib.List<unowned GOF.File> selection = get_files_for_action (); |
4643 | + GOF.File file = selection.data as GOF.File; |
4644 | + |
4645 | + Gtk.DialogFlags flags = Gtk.DialogFlags.MODAL | |
4646 | + Gtk.DialogFlags.DESTROY_WITH_PARENT | |
4647 | + Gtk.DialogFlags.USE_HEADER_BAR; |
4648 | + |
4649 | + var dialog = new Gtk.AppChooserDialog (window, flags, file.location); |
4650 | + dialog.set_heading (_("Select an application")); |
4651 | + |
4652 | + var check_default = new Gtk.CheckButton.with_label (_("Set as default")); |
4653 | + dialog.get_content_area ().pack_start (check_default, false, false, 0); |
4654 | + dialog.show_all (); |
4655 | + |
4656 | + int response = dialog.run (); |
4657 | + |
4658 | + if (response == Gtk.ResponseType.OK) { |
4659 | + var app =dialog.get_app_info (); |
4660 | + if (check_default.get_active ()) { |
4661 | + try { |
4662 | + app.set_as_default_for_type (file.get_ftype ()); |
4663 | + } |
4664 | + catch (GLib.Error error) { |
4665 | + critical ("Could not set as default: %s", error.message); |
4666 | + } |
4667 | + } |
4668 | + open_files_with (app, selection); |
4669 | + } |
4670 | + |
4671 | + dialog.destroy (); |
4672 | + } |
4673 | + |
4674 | + private void on_common_action_bookmark (GLib.SimpleAction action, GLib.Variant? param) { |
4675 | + if (selected_files != null) |
4676 | + window.sidebar.add_uri (selected_files.data.uri); |
4677 | + else |
4678 | + window.sidebar.add_uri (slot.directory.file.uri); |
4679 | + } |
4680 | + |
4681 | + /** Background actions */ |
4682 | + |
4683 | + private void change_state_show_hidden (GLib.SimpleAction action) { |
4684 | + window.change_state_show_hidden (action); |
4685 | + } |
4686 | + |
4687 | + private void on_background_action_new (GLib.SimpleAction action, GLib.Variant? param) { |
4688 | + switch (param.get_string ()) { |
4689 | + case "FOLDER": |
4690 | + new_empty_folder (); |
4691 | + break; |
4692 | + |
4693 | + case "FILE": |
4694 | + new_empty_file (); |
4695 | + break; |
4696 | + |
4697 | + default: |
4698 | + break; |
4699 | + } |
4700 | + } |
4701 | + |
4702 | + private void on_background_action_create_from (GLib.SimpleAction action, GLib.Variant? param) { |
4703 | + int index = int.parse (param.get_string ()); |
4704 | + create_from_template (templates.nth_data ((uint)index)); |
4705 | + } |
4706 | + |
4707 | + private void on_background_action_sort_by_changed (GLib.SimpleAction action, GLib.Variant? val) { |
4708 | + string sort = val.get_string (); |
4709 | + set_sort (sort, false); |
4710 | + } |
4711 | + private void on_background_action_reverse_changed (GLib.SimpleAction action, GLib.Variant? val) { |
4712 | + set_sort (null, true); |
4713 | + } |
4714 | + |
4715 | + private void set_sort (string? col_name, bool reverse) { |
4716 | + int sort_column_id; |
4717 | + Gtk.SortType sort_order; |
4718 | + |
4719 | + if (model.get_sort_column_id (out sort_column_id, out sort_order)) { |
4720 | + if (col_name != null) |
4721 | + sort_column_id = get_column_id_from_string (col_name); |
4722 | + |
4723 | + if (reverse) { |
4724 | + if (sort_order == Gtk.SortType.ASCENDING) |
4725 | + sort_order = Gtk.SortType.DESCENDING; |
4726 | + else |
4727 | + sort_order = Gtk.SortType.ASCENDING; |
4728 | + } |
4729 | + |
4730 | + model.set_sort_column_id (sort_column_id, sort_order); |
4731 | + } |
4732 | + } |
4733 | + |
4734 | + /** Common actions */ |
4735 | + |
4736 | + private void on_common_action_open_in (GLib.SimpleAction action, GLib.Variant? param) { |
4737 | + default_app = null; |
4738 | + |
4739 | + switch (param.get_string ()) { |
4740 | + case "TAB": |
4741 | + activate_selected_items (Marlin.OpenFlag.NEW_TAB, get_files_for_action ()); |
4742 | + break; |
4743 | + |
4744 | + case "WINDOW": |
4745 | + activate_selected_items (Marlin.OpenFlag.NEW_WINDOW, get_files_for_action ()); |
4746 | + break; |
4747 | + |
4748 | + case "TERMINAL": |
4749 | + open_selected_in_terminal (get_files_for_action ()); |
4750 | + break; |
4751 | + |
4752 | + default: |
4753 | + break; |
4754 | + } |
4755 | + } |
4756 | + |
4757 | + private void open_selected_in_terminal (GLib.List<unowned GOF.File> selection = get_selected_files ()) { |
4758 | + var terminal = new GLib.DesktopAppInfo (Marlin.OPEN_IN_TERMINAL_DESKTOP_ID); |
4759 | + |
4760 | + if (terminal != null) |
4761 | + open_files_with (terminal, selection); |
4762 | + } |
4763 | + |
4764 | + private void on_common_action_properties (GLib.SimpleAction action, GLib.Variant? param) { |
4765 | + new Marlin.View.PropertiesWindow (get_files_for_action (), this, window); |
4766 | + } |
4767 | + |
4768 | + private void on_common_action_copy (GLib.SimpleAction action, GLib.Variant? param) { |
4769 | + clipboard.copy_files (get_selected_files_for_transfer (get_files_for_action ())); |
4770 | + } |
4771 | + |
4772 | + private void on_common_action_paste_into (GLib.SimpleAction action, GLib.Variant? param) { |
4773 | + var file = get_files_for_action ().nth_data (0); |
4774 | + |
4775 | + if (file != null && clipboard.get_can_paste ()) { |
4776 | + prepare_to_select_added_files (); |
4777 | + if (file.is_folder () && !clipboard.has_file (file)) |
4778 | + clipboard.paste_files (file.get_target_location (), this as Gtk.Widget, null); |
4779 | + else |
4780 | + clipboard.paste_files (slot.directory.location, this as Gtk.Widget, null); |
4781 | + } |
4782 | + } |
4783 | + |
4784 | + |
4785 | + private void on_directory_file_added (GOF.Directory.Async dir, GOF.File file) { |
4786 | + add_file (file, dir); |
4787 | + } |
4788 | + |
4789 | + private void on_directory_file_loaded (GOF.Directory.Async dir, GOF.File file) { |
4790 | + select_added_files = false; |
4791 | + add_file (file, dir); |
4792 | + } |
4793 | + |
4794 | + private void on_directory_file_changed (GOF.Directory.Async dir, GOF.File file) { |
4795 | + remove_marlin_icon_info_cache (file); |
4796 | + model.file_changed (file, dir); |
4797 | + /* 2nd parameter is for returned request id if required - we do not use it? */ |
4798 | + /* This is required if we need to dequeue the request */ |
4799 | + thumbnailer.queue_file (file, null, false); |
4800 | + } |
4801 | + |
4802 | + private void on_directory_file_icon_changed (GOF.Directory.Async dir, GOF.File file) { |
4803 | + model.file_changed (file, dir); |
4804 | + } |
4805 | + |
4806 | + private void on_directory_file_deleted (GOF.Directory.Async dir, GOF.File file) { |
4807 | + remove_marlin_icon_info_cache (file); |
4808 | + model.remove_file (file, dir); |
4809 | + if (file.is_folder ()) { |
4810 | + var file_dir = GOF.Directory.Async.cache_lookup (file.location); |
4811 | + if (file_dir != null) { |
4812 | + file_dir.purge_dir_from_cache (); |
4813 | + slot.folder_deleted (file, file_dir); |
4814 | + } |
4815 | + } |
4816 | + } |
4817 | + |
4818 | + private void on_directory_done_loading (GOF.Directory.Async dir) { |
4819 | + debug ("DV directory done loading %s", dir.file.uri); |
4820 | + dir.file_loaded.disconnect (on_directory_file_loaded); |
4821 | + in_trash = (dir.file.uri == Marlin.TRASH_URI); /* trash cannot be subdirectory */ |
4822 | + thaw_tree (); |
4823 | + queue_draw (); |
4824 | + } |
4825 | + |
4826 | + private void on_directory_thumbs_loaded (GOF.Directory.Async dir) { |
4827 | + Marlin.IconInfo.infos_caches (); |
4828 | + } |
4829 | + |
4830 | + /** Handle zoom level change */ |
4831 | + private void on_zoom_level_changed (Marlin.ZoomLevel zoom) { |
4832 | + model.set_property ("size", icon_size); |
4833 | + change_zoom_level (); |
4834 | + |
4835 | + if (get_realized ()) |
4836 | + load_thumbnails (slot.directory, zoom); |
4837 | + } |
4838 | + |
4839 | + /** Handle Preference changes */ |
4840 | + private void on_show_hidden_files_changed (GLib.Object prefs, GLib.ParamSpec pspec) { |
4841 | + bool show = (prefs as GOF.Preferences).show_hidden_files; |
4842 | + if (!show) { |
4843 | + block_model (); |
4844 | + model.clear (); |
4845 | + } |
4846 | + |
4847 | + directory_hidden_changed (slot.directory, show); |
4848 | + if (loaded_subdirectories != null) |
4849 | + loaded_subdirectories.@foreach ((dir) => { |
4850 | + directory_hidden_changed (dir, show); |
4851 | + }); |
4852 | + |
4853 | + if (!show) |
4854 | + unblock_model (); |
4855 | + |
4856 | + action_set_state (background_actions, "show_hidden", show); |
4857 | + } |
4858 | + |
4859 | + private void directory_hidden_changed (GOF.Directory.Async dir, bool show) { |
4860 | + dir.file_loaded.connect (on_directory_file_loaded); /* disconnected by on_done_loading callback.*/ |
4861 | + |
4862 | + if (show) |
4863 | + dir.load_hiddens (); |
4864 | + else |
4865 | + dir.load (); |
4866 | + } |
4867 | + |
4868 | + private void on_interpret_desktop_files_changed () { |
4869 | + slot.directory.update_desktop_files (); |
4870 | + } |
4871 | + |
4872 | + /** Handle popup menu events */ |
4873 | + private bool on_popup_menu () { |
4874 | + Gdk.Event event = Gtk.get_current_event (); |
4875 | + show_or_queue_context_menu (event); |
4876 | + return true; |
4877 | + } |
4878 | + |
4879 | + /** Handle Button events */ |
4880 | + private bool on_drag_timeout_button_release (Gdk.EventButton event) { |
4881 | + /* Only active during drag timeout */ |
4882 | + cancel_drag_timer (); |
4883 | + |
4884 | + if (drag_button == Gdk.BUTTON_SECONDARY) |
4885 | + show_context_menu (event); |
4886 | + |
4887 | + return true; |
4888 | + } |
4889 | + |
4890 | + private bool on_button_press_event (Gdk.EventButton event) { |
4891 | + /* Extra mouse button action: button8 = "Back" button9 = "Forward" */ |
4892 | + GLib.Action? action = null; |
4893 | + GLib.SimpleActionGroup main_actions = window.get_action_group (); |
4894 | + if (event.type == Gdk.EventType.BUTTON_PRESS) { |
4895 | + if (event.button == 8) |
4896 | + action = main_actions.lookup_action ("Back"); |
4897 | + else if (event.button == 9) |
4898 | + action = main_actions.lookup_action ("Forward"); |
4899 | + |
4900 | + if (action != null) { |
4901 | + action.activate (null); |
4902 | + return true; |
4903 | + } |
4904 | + } |
4905 | + return false; |
4906 | + } |
4907 | + |
4908 | +/** Handle Motion events */ |
4909 | + private bool on_drag_timeout_motion_notify (Gdk.EventMotion event) { |
4910 | + /* Only active during drag timeout */ |
4911 | + Gdk.DragContext context; |
4912 | + var widget = get_real_view (); |
4913 | + int x = (int)event.x; |
4914 | + int y = (int)event.y; |
4915 | + |
4916 | + if (Gtk.drag_check_threshold (widget, drag_x, drag_y, x, y)) { |
4917 | + cancel_drag_timer (); |
4918 | + should_activate = false; |
4919 | + var target_list = new Gtk.TargetList (drag_targets); |
4920 | + var actions = file_drag_actions; |
4921 | + |
4922 | + if (drag_button == 3) |
4923 | + actions |= Gdk.DragAction.ASK; |
4924 | + |
4925 | + context = Gtk.drag_begin_with_coordinates (widget, |
4926 | + target_list, |
4927 | + actions, |
4928 | + drag_button, |
4929 | + (Gdk.Event) event, |
4930 | + x, y); |
4931 | + return true; |
4932 | + } else |
4933 | + return false; |
4934 | + } |
4935 | + |
4936 | +/** Handle TreeModel events */ |
4937 | + protected virtual void on_row_deleted (Gtk.TreePath path) { |
4938 | + GLib.List<Gtk.TreePath>? selected_paths = get_selected_paths (); |
4939 | + selection_before_delete = null; |
4940 | + |
4941 | + /* Do nothing if the deleted row is not selected or there is more than one file selected */ |
4942 | + if (selected_paths == null || |
4943 | + selected_paths.length () != 1 || |
4944 | + selected_paths.find_custom (path, Gtk.TreePath.compare) == null) |
4945 | + |
4946 | + return; |
4947 | + |
4948 | + /* Create a copy the path (we're not allowed to modify it in this handler) */ |
4949 | + Gtk.TreePath path_copy = path.copy (); |
4950 | + |
4951 | + /* Remember the selected path so that it can be restored after the row has |
4952 | + * been removed. If the first row is removed, select the first row after the |
4953 | + * removal, if any other row is removed, select the row before that one */ |
4954 | + path_copy.prev (); |
4955 | + selection_before_delete = path_copy.copy (); |
4956 | + } |
4957 | + |
4958 | +/** Handle clipboard signal */ |
4959 | + private void on_clipboard_changed () { |
4960 | + update_menu_actions (); |
4961 | + /* show possible change in appearance of cut items */ |
4962 | + queue_draw (); |
4963 | + } |
4964 | + |
4965 | +/** Handle Selection changes */ |
4966 | + public void notify_selection_changed () { |
4967 | + selection_was_removed = false; |
4968 | + |
4969 | + if (!get_realized ()) |
4970 | + return; |
4971 | + |
4972 | + if (updates_frozen) |
4973 | + return; |
4974 | + |
4975 | + update_menu_actions (); |
4976 | + window.selection_changed (get_selected_files ()); |
4977 | + } |
4978 | + |
4979 | + /** Handle size allocation event */ |
4980 | + private void on_size_allocate (Gtk.Allocation allocation) { |
4981 | + schedule_thumbnail_timeout (); |
4982 | + } |
4983 | + |
4984 | +/** DRAG AND DROP */ |
4985 | + |
4986 | + /** Handle Drag source signals*/ |
4987 | + |
4988 | + private void on_drag_begin (Gdk.DragContext context) { |
4989 | + drag_has_begun = true; |
4990 | + should_activate = false; |
4991 | + drag_file_list = get_selected_files_for_transfer (); |
4992 | + |
4993 | + if (drag_file_list == null) |
4994 | + return; |
4995 | + |
4996 | + GOF.File file = drag_file_list.first ().data; |
4997 | + |
4998 | + if (file != null && file.pix != null) |
4999 | + Gtk.drag_set_icon_pixbuf (context, file.pix, 0, 0); |
5000 | + else |
I can see a menubar and a GNOME-style appmenu. That's a pretty undesirable change.
I get an "edit"/I-beam anytime I'm anywhere over the icon view. That should probably only happen over the label (which btw, clicking the label to edit is awesome).
When there's no back/forward history the respective button should become insensitive (regression)
There's no visible rubberband for selection files/folders in any view (regression)
No Ctrl F to search (regression)
"Open In" menu is interesting. Does this show the same items as "Open With" would, but with the addition of "New Tab" and "New Window"? It's possible to get both menus which shows the duplicate entry "Terminal". I think we should choose one or the other.
I like that the selection emblems automatically appear based on icon size. That's a pretty cool feature.
Not being able to drag multiple items is a regression and a pretty big one. I think this is pretty important functionality we need to preserve.
I don't think we need to automatically switch to a certain view when in a directory. Users should be in control of the view imo.
I can no longer show hidden files by right clicking in the view (regression)
If I have a selection and then right click on the view, the selection should be lost. It's kind of confusing to see context items for the selection when I haven't right clicked on the selection.
Submenus don't need ellipsis. (Open with, Open in, New etc)
I don't think we need to specify "Empty Folder" since there isn't really a way to create a populated folder. "Folder" is probably okay here.