Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File dialog locations #2

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
101 changes: 46 additions & 55 deletions dialog/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"

"fyne.io/fyne"
Expand Down Expand Up @@ -84,14 +83,6 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
name := f.fileName.(*widget.Entry).Text
path, _ := storage.Child(f.dir, name)

// On windows replace '\\' with '/'
if runtime.GOOS == "windows" {
pathString := path.String()
pathString = strings.ReplaceAll(pathString, "\\\\", "/")
pathString = strings.ReplaceAll(pathString, "\\", "/")
path = storage.NewURI(pathString)
}

exists, _ := storage.Exists(path)

_, err := storage.ListerForURI(path)
Expand Down Expand Up @@ -131,12 +122,6 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
}
path := f.selected.location
// On windows replace '\\' with '/'
if runtime.GOOS == "windows" {
pathString := path.String()
pathString = strings.ReplaceAll(pathString, "\\\\", "/")
pathString = strings.ReplaceAll(pathString, "\\", "/")
path = storage.NewURI(pathString)
}
callback(storage.OpenFileFromURI(path))
}
})
Expand Down Expand Up @@ -192,49 +177,62 @@ func (f *fileDialog) makeUI() fyne.CanvasObject {
}

func (f *fileDialog) loadFavorites() ([]fyne.CanvasObject, error) {
osHome, err := os.UserHomeDir()
if err != nil {
return nil, err
}
var home fyne.ListableURI
var documents fyne.ListableURI
var downloads fyne.ListableURI
var osHome string
var err, err1 error

home, err := storage.ListerForURI(storage.NewURI("file://" + osHome))
if err != nil {
return nil, err
}
osHome, err = os.UserHomeDir()

documentsURI, err := storage.Child(home, "Documents")
if err != nil {
return nil, err
}
documents, err := storage.ListerForURI(documentsURI)
if err != nil {
return nil, err
}

downloadsURI, err := storage.Child(home, "Downloads")
if err != nil {
return nil, err
}
downloads, err := storage.ListerForURI(downloadsURI)
if err != nil {
return nil, err
if err == nil {
home, err1 = storage.ListerForURI(storage.NewURI("file://" + osHome))
if err1 == nil {
var documentsURI fyne.URI
documentsURI, err1 = storage.Child(home, "Documents")
if err1 == nil {
documents, err1 = storage.ListerForURI(documentsURI)
if err1 != nil {
err = err1
}
} else {
err = err1
}
var downloadsURI fyne.URI
downloadsURI, err1 = storage.Child(home, "Downloads")
if err1 == nil {
downloads, err1 = storage.ListerForURI(downloadsURI)
if err1 != nil {
err = err1
}
} else {
err = err1
}
} else {
err = err1
}
}

places := []fyne.CanvasObject{
var places []fyne.CanvasObject

makeFavoriteButton("Home", theme.HomeIcon(), func() {
if home != nil {
places = append(places, makeFavoriteButton("Home", theme.HomeIcon(), func() {
f.setDirectory(home)
}),
makeFavoriteButton("Documents", theme.DocumentIcon(), func() {
}))
}
if documents != nil {
places = append(places, makeFavoriteButton("Documents", theme.DocumentIcon(), func() {
f.setDirectory(documents)
}),
makeFavoriteButton("Downloads", theme.DownloadIcon(), func() {
}))
}
if downloads != nil {
places = append(places, makeFavoriteButton("Downloads", theme.DownloadIcon(), func() {
f.setDirectory(downloads)
}),
}))
}

places = append(places, f.loadPlaces()...)
return places, nil
return places, err
}

func (f *fileDialog) refreshDir(dir fyne.ListableURI) {
Expand Down Expand Up @@ -289,17 +287,10 @@ func (f *fileDialog) setDirectory(dir fyne.ListableURI) error {

f.breadcrumb.Children = nil

if dir.Scheme() != "file" {
return fmt.Errorf("scheme for directory was not file://")
}

localdir := dir.String()[len(dir.Scheme())+3:]
if runtime.GOOS == "windows" {
localdir = strings.ReplaceAll(localdir, "/", "\\")
}

buildDir := filepath.VolumeName(localdir)
for i, d := range strings.Split(localdir, string(filepath.Separator)) {
for i, d := range strings.Split(localdir, "/") {
if d == "" {
if i > 0 { // what we get if we split "/"
break
Expand Down
27 changes: 18 additions & 9 deletions dialog/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,22 @@ func TestShowFileOpen(t *testing.T) {
buttons := ui.Objects[2].(*fyne.Container).Objects[0].(*widget.Box)
open := buttons.Children[1].(*widget.Button)

breadcrumb := ui.Objects[3].(*fyne.Container).Objects[0].(*widget.ScrollContainer).Content.(*widget.Box)
assert.Greater(t, len(breadcrumb.Children), 0)

wd, err := os.Getwd()
if runtime.GOOS == "windows" {
// on windows os.Getwd() returns '\'
wd = strings.ReplaceAll(wd, "\\", "/")
}
assert.Nil(t, err)
components := strings.Split(wd, "/")
if assert.Equal(t, len(components), len(breadcrumb.Children)) {
for i := range components {
assert.Equal(t, components[i], breadcrumb.Children[i].(*widget.Button).Text)
}
}

files := ui.Objects[3].(*fyne.Container).Objects[1].(*widget.ScrollContainer).Content.(*fyne.Container)
assert.Greater(t, len(files.Objects), 0)

Expand Down Expand Up @@ -210,16 +226,9 @@ func TestShowFileOpen(t *testing.T) {
assert.Nil(t, win.Canvas().Overlays().Top())
assert.Nil(t, openErr)

targetLocationString := target.location.String()
// Replace all '\\' with '/' on windows since the dialog
// will return a URI with only '/'
if runtime.GOOS == "windows" {
targetLocationString = strings.ReplaceAll(targetLocationString, "\\\\", "/")
targetLocationString = strings.ReplaceAll(targetLocationString, "\\", "/")
}
assert.Equal(t, targetLocationString, chosen.URI().String())
assert.Equal(t, target.location.String(), chosen.URI().String())

err := chosen.Close()
err = chosen.Close()
assert.Nil(t, err)
}

Expand Down
2 changes: 1 addition & 1 deletion dialog/fileitem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestNewFileItem_Folder(t *testing.T) {
test.Tap(item)
assert.False(t, item.isCurrent)
assert.Equal(t, (*fileDialogItem)(nil), f.selected)
assert.Equal(t, currentDir, f.dir.String()[len(f.dir.Scheme())+3:])
assert.Equal(t, storage.NewURI("file://"+currentDir).String(), f.dir.String())
}

func TestNewFileItem_ParentFolder(t *testing.T) {
Expand Down
31 changes: 13 additions & 18 deletions storage/uri.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ type uri struct {
// NewURI creates a new URI from the given string representation.
// This could be a URI from an external source or one saved from URI.String()
func NewURI(u string) fyne.URI {
// URIs are supposed to use forward slashes. On Windows, it
// should be OK to use the platform native filepath with UNIX
// or NT sytle paths, with / or \, but when we reconstruct
// the URI, we want to have / only.
if runtime.GOOS == "windows" {
// seems that sometimes we end up with
// double-backslashes
u = strings.ReplaceAll(u, "\\\\", "/")
u = strings.ReplaceAll(u, "\\", "/")
}
return &uri{raw: u}
}

Expand Down Expand Up @@ -81,8 +91,6 @@ func parentGeneric(location string) (string, error) {
components := strings.Split(location, "/")

if len(components) == 1 {
// trimmed <= 2 makes sure we handle UNIX-style paths on
// Windows correctly
return "", URIRootError
}

Expand All @@ -104,11 +112,6 @@ func Parent(u fyne.URI) (fyne.URI, error) {
s := u.String()

// trim trailing slash
if runtime.GOOS == "windows" {
if s[len(s)-1] == '\\' {
s = s[0 : len(s)-1]
}
}
if s[len(s)-1] == '/' {
s = s[0 : len(s)-1]
}
Expand All @@ -125,23 +128,15 @@ func Parent(u fyne.URI) (fyne.URI, error) {
if u.Scheme() == "file" {
// use the system native path resolution
parent = filepath.Dir(s)
if parent[len(parent)-1] != filepath.Separator {
parent += "/"
}

// only root is it's own parent
if filepath.Clean(parent) == filepath.Clean(s) {
return nil, URIRootError
}

// URIs are supposed to use forward slashes. On Windows, it
// should be OK to use the platform native filepath with UNIX
// or NT sytle paths, with / or \, but when we reconstruct
// the URI, we want to have / only.
if runtime.GOOS == "windows" {
// seems that sometimes we end up with
// double-backslashes
parent = strings.ReplaceAll(parent, "\\\\", "/")
parent = strings.ReplaceAll(parent, "\\", "/")
}

} else {
var err error
parent, err = parentGeneric(s)
Expand Down
41 changes: 36 additions & 5 deletions storage/uri_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,43 @@ func TestURI_Parent(t *testing.T) {

parent, err := storage.Parent(storage.NewURI("file:///foo/bar/baz"))
assert.Nil(t, err)
assert.Equal(t, "file:///foo/bar", parent.String())
assert.Equal(t, "file:///foo/bar/", parent.String())

parent, err = storage.Parent(storage.NewURI("file:///foo/bar/baz/"))
assert.Nil(t, err)
assert.Equal(t, "file:///foo/bar", parent.String())
assert.Equal(t, "file:///foo/bar/", parent.String())

parent, err = storage.Parent(storage.NewURI("file://C:/foo/bar/baz/"))
assert.Nil(t, err)
assert.Equal(t, "file://C:/foo/bar", parent.String())
assert.Equal(t, "file://C:/foo/bar/", parent.String())

parent, err = storage.Parent(storage.NewURI("http://foo/bar/baz/"))
assert.Nil(t, err)
assert.Equal(t, "http://foo/bar/", parent.String())

parent, err = storage.Parent(storage.NewURI("http:////foo/bar/baz/"))
assert.Nil(t, err)
assert.Equal(t, "http://foo/bar/", parent.String())

_, err = storage.Parent(storage.NewURI("http://foo"))
assert.Equal(t, storage.URIRootError, err)

_, err = storage.Parent(storage.NewURI("http:///"))
assert.Equal(t, storage.URIRootError, err)

parent, err = storage.Parent(storage.NewURI("https://///foo/bar/"))
assert.Nil(t, err)
assert.Equal(t, "https:///foo/", parent.String())

if runtime.GOOS == "windows" {
// Only the Windows version of filepath will know how to handle
// backslashes.
parent, err = storage.Parent(storage.NewURI("file://C:\\foo\\bar\\baz\\"))
uri := storage.NewURI("file://C:\\foo\\bar\\baz\\")
assert.Equal(t, "file://C:/foo/bar/baz/", uri.String())

parent, err = storage.Parent(uri)
assert.Nil(t, err)
assert.Equal(t, "file://C:/foo/bar", parent.String())
assert.Equal(t, "file://C:/foo/bar/", parent.String())
}

_, err = storage.Parent(storage.NewURI("file:///"))
Expand Down Expand Up @@ -104,4 +125,14 @@ func TestURI_Child(t *testing.T) {

p, _ = storage.Child(storage.NewURI("file:///foo/bar/"), "baz")
assert.Equal(t, "file:///foo/bar/baz", p.String())

if runtime.GOOS == "windows" {
// Only the Windows version of filepath will know how to handle
// backslashes.
uri := storage.NewURI("file://C:\\foo\\bar\\")
assert.Equal(t, "file://C:/foo/bar/", uri.String())

p, _ = storage.Child(uri, "baz")
assert.Equal(t, "file://C:/foo/bar/baz", p.String())
}
}