Ejemplo n.º 1
0
func (f *frontend) Prompt(title, folder string, flags int) []string {
	w := f.windows[backend.GetEditor().ActiveWindow()]
	obj := w.qw.ObjectByName("fileDialog")
	obj.Set("title", title)
	obj.Set("folder", "file://"+folder)
	obj.Set("selectExisting", flags&backend.PROMPT_SAVE_AS == 0)
	obj.Set("selectFolder", flags&backend.PROMPT_ONLY_FOLDER == 1)
	obj.Set("selectMultiple", flags&backend.PROMPT_SELECT_MULTIPLE == 1)

	f.promptWaitGroup.Add(1)
	obj.Call("open")
	f.promptWaitGroup.Wait()

	if f.promptResult != "accepted" {
		return nil
	}

	res := obj.List("fileUrls")
	files := make([]string, res.Len())
	res.Convert(&files)
	for i, file := range files {
		if file[:7] == "file://" {
			files[i] = file[7:]
		}
	}
	log.Fine("Selected %s files", files)
	return files
}
Ejemplo n.º 2
0
func (f *frontend) message(text string, icon, btns int) string {
	cbs := make(map[string]int)
	if btns&okButton != 0 {
		cbs["accepted"] = 1
	}
	if btns&cancelButton != 0 {
		cbs["rejected"] = 0
	}

	w := f.windows[backend.GetEditor().ActiveWindow()]
	obj := w.qw.ObjectByName("messageDialog")
	obj.Set("text", text)
	obj.Set("icon", icon)
	obj.Set("standardButtons", btns)

	f.promptWaitGroup.Add(1)
	obj.Call("open")
	f.promptWaitGroup.Wait()

	log.Fine("returning %d from dialog", f.promptResult)
	return f.promptResult
}
Ejemplo n.º 3
0
func (f *frontend) loop() (err error) {
	ed := backend.GetEditor()
	// TODO: As InitCallback doc says initiation code to be deferred until
	// after the UI is up and running. but because we dont have any
	// scheme we are initing editor before the UI comes up.
	ed.Init()
	ed.SetDefaultPath("../packages/Default")
	ed.SetUserPath("../packages/User")
	ed.SetClipboardFuncs(clipboard.WriteAll, clipboard.ReadAll)

	// Some packages(e.g Vintageos) need available window and view at start
	// so we need at least one window and view before loading packages.
	// Sublime text also has available window view on startup
	w := ed.NewWindow()
	w.NewFile()
	ed.AddPackagesPath("../packages")

	ed.SetFrontend(f)
	ed.LogInput(false)
	ed.LogCommands(false)

	c := ed.Console()
	f.Console = newView(c)
	c.AddObserver(f.Console)
	c.AddObserver(f)

	var (
		engine    *qml.Engine
		component qml.Object
		// WaitGroup keeping track of open windows
		wg sync.WaitGroup
	)

	// create and setup a new engine, destroying
	// the old one if one exists.
	//
	// This is needed to re-load qml files to get
	// the new file contents from disc as otherwise
	// the old file would still be what is referenced.
	newEngine := func() (err error) {
		if engine != nil {
			log.Debug("calling destroy")
			// TODO(.): calling this appears to make the editor *very* crash-prone, just let it leak for now
			// engine.Destroy()
			engine = nil
		}
		log.Debug("calling newEngine")
		engine = qml.NewEngine()
		engine.On("quit", f.Quit)
		log.Fine("setvar frontend")
		engine.Context().SetVar("frontend", f)

		log.Fine("loading %s", qmlWindowFile)
		component, err = engine.LoadFile(qmlWindowFile)
		return
	}
	if err := newEngine(); err != nil {
		log.Error("Error on creating new engine: %s", err)
		panic(err)
	}

	addWindow := func(bw *backend.Window) {
		w := newWindow(bw)
		f.windows[bw] = w
		w.launch(&wg, component)
	}

	backend.OnNew.Add(f.onNew)
	backend.OnClose.Add(f.onClose)
	backend.OnLoad.Add(f.onLoad)
	backend.OnSelectionModified.Add(f.onSelectionModified)
	backend.OnNewWindow.Add(addWindow)
	backend.OnStatusChanged.Add(f.onStatusChanged)

	// we need to add windows and views that are added before we registered
	// actions for OnNewWindow and OnNew events
	for _, w := range ed.Windows() {
		addWindow(w)
		for _, v := range w.Views() {
			f.onNew(v)
			f.onLoad(v)
		}
	}

	defer func() {
		fmt.Println(util.Prof)
	}()

	// The rest of code is related to livereloading qml files
	// TODO: this doesnt work currently
	watch, err := fsnotify.NewWatcher()
	if err != nil {
		log.Error("Unable to create file watcher: %s", err)
		return
	}
	defer watch.Close()
	watch.Add("qml")
	defer watch.Remove("qml")

	reloadRequested := false
	waiting := false

	go func() {
		// reloadRequested = true
		// f.Quit()

		lastTime := time.Now()

		for {

			select {
			case ev := <-watch.Events:
				if time.Now().Sub(lastTime) < 1*time.Second {
					// quitting too frequently causes crashes
					lastTime = time.Now()
					continue
				}
				if strings.HasSuffix(ev.Name, ".qml") && ev.Op == fsnotify.Write && ev.Op != fsnotify.Chmod && !reloadRequested && waiting {
					reloadRequested = true
					f.Quit()
					lastTime = time.Now()
				}
			}
		}
	}()

	for {
		// Reset reload status
		reloadRequested = false

		log.Debug("Waiting for all windows to close")
		// wg would be the WaitGroup all windows belong to, so first we wait for
		// all windows to close.
		waiting = true
		wg.Wait()
		waiting = false
		log.Debug("All windows closed. reloadRequest: %v", reloadRequested)
		// then we check if there's a reload request in the pipe
		if !reloadRequested || len(f.windows) == 0 {
			// This would be a genuine exit; all windows closed by the user
			break
		}

		// *We* closed all windows because we want to reload freshly changed qml
		// files.
		for {
			log.Debug("Calling newEngine")
			if err := newEngine(); err != nil {
				// Reset reload status
				reloadRequested = false
				waiting = true
				log.Error(err)
				for !reloadRequested {
					// This loop allows us to re-try reloading
					// if there was an error in the file this time,
					// we just loop around again when we receive the next
					// reload request (ie on the next save of the file).
					time.Sleep(time.Second)
				}
				waiting = false
				continue
			}
			log.Debug("break")
			break
		}
		log.Debug("re-launching all windows")
		// Succeeded loading the file, re-launch all windows
		for _, w := range f.windows {
			w.launch(&wg, component)

			for _, bv := range w.Back().Views() {
				f.onNew(bv)
				f.onLoad(bv)

			}
		}
	}

	return
}