Skip to content

Commit

Permalink
Merge branch 'ignoreeditor'
Browse files Browse the repository at this point in the history
  • Loading branch information
kozec committed Sep 28, 2014
2 parents 5136a20 + 8f11647 commit 20f232e
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 16 deletions.
18 changes: 18 additions & 0 deletions app.glade
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,17 @@
<signal name="activate" handler="cb_menu_popup_edit_repo" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="menu-popup-edit-ignored">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Edit _Ingnore Patterns</property>
<property name="use_underline">True</property>
<property name="image">menu-popup-edit-ignored-image</property>
<property name="always_show_image">True</property>
<signal name="activate" handler="cb_menu_popup_edit_ignored" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="menu-popup-rescan-repo">
<property name="visible">True</property>
Expand Down Expand Up @@ -589,6 +600,13 @@
<property name="stock">gtk-refresh</property>
</object>

<object class="GtkImage" id="menu-popup-edit-ignored-image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_size">1</property>
<property name="pixbuf">icons/eye.png</property>
</object>

<object class="GtkImage" id="menu-popup-show-id-image">
<property name="visible">True</property>
<property name="can_focus">False</property>
Expand Down
136 changes: 136 additions & 0 deletions ignore-editor.glade
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkTextBuffer" id="tbPatterns">
</object>
<object class="GtkDialog" id="dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Ignore Patterns</property>
<property name="role">node-edit</property>
<property name="modal">True</property>
<property name="default_width">600</property>
<property name="default_height">550</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="btClose">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="cb_btClose_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="btSave">
<property name="label">gtk-save</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="btSave_clicked_cb" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="tvPatterns">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="buffer">tbPatterns</property>
<property name="accepts_tab">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_top">15</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">See &lt;a href="https://discourse.syncthing.net/t/excluding-files-from-synchronization-ignoring/80"&gt;Syncthing documentation&lt;/a&gt; for list of supported patterns</property>
<property name="use_markup">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="lblLocation">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">5</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">File location: </property>
<property name="use_markup">True</property>
<property name="ellipsize">end</property>
<signal name="activate-link" handler="on_lblLocation_activate_link" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
1 change: 1 addition & 0 deletions syncthing_gtk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from configuration import Configuration
from iddialog import IDDialog
from about import AboutDialog
from ignoreeditor import IgnoreEditor
from ribar import RIBar
from timermgr import TimerManager
from statusicon import StatusIcon
Expand Down
9 changes: 9 additions & 0 deletions syncthing_gtk/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,15 @@ def cb_menu_popup_edit_repo(self, *a):
# Editing repository
self.open_editor("repo-edit", self.rightclick_box["id"])

def cb_menu_popup_edit_ignored(self, *a):
""" Handler for 'edit ignore patterns' context menu item """
e = IgnoreEditor(self,
self.rightclick_box["id"],
self.rightclick_box["folder"],
)
e.load()
e.show(self["window"])

def cb_menu_popup_edit_node(self, *a):
""" Handler for other 'edit' context menu item """
# Editing node
Expand Down
42 changes: 26 additions & 16 deletions syncthing_gtk/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -850,19 +850,6 @@ def _syncthing_cb_config_in_sync(self, data):
# Not in sync...
self.emit("config-out-of-sync")

def _syncthing_cb_config_written(self, data, callback, errorcallback, calbackdata):
self.check_config()
if calbackdata == None:
callback()
else:
callback(*calbackdata)

def _syncthing_cb_config_write_failed(self, exception, command, data, callback, errorcallback, calbackdata):
if errorcallback == None:
errorcallback(exception)
else:
errorcallback(exception, *calbackdata)

def _syncthing_cb_rescan_error(self, exception, command, data, repo_id):
print >>sys.stderr, "Warning: Failed to rescan repository %s: %s" % (repo_id, exception.response)
self.emit("error", "Warning: Failed to rescan repository %s: %s" % (repo_id, exception.response))
Expand Down Expand Up @@ -991,11 +978,34 @@ def read_config(self, callback, error_callback=None, *calbackdata):
def write_config(self, config, callback, error_callback=None, *calbackdata):
"""
Asynchronously POSTs new configuration to daemon. Calls
callback() with data decoded from json on success,
error_callback(exception) on failure.
callback() on success, error_callback(exception) on failure.
Should cause 'config-out-of-sync' event to be raised ASAP.
"""
self._rest_post("config", config, self._syncthing_cb_config_written, self._syncthing_cb_config_write_failed, callback, error_callback, calbackdata)
def run_before(data, *a):
self.check_config()
callback(*calbackdata)
self._rest_post("config", config, run_before, error_callback, *calbackdata)

def read_stignore(self, repo_id, callback, error_callback=None, *calbackdata):
"""
Asynchronously reads .stignore data from from daemon.
Calls callback(text) with .stignore content on success,
error_callback(exception) on failure
"""
def r_filter(data, *a):
if "ignore" in data and not data["ignore"] is None:
callback("\n".join(data["ignore"]).strip(" \t\n"), *a)
else:
callback("", *a)
self._rest_request("ignores?repo=%s" % (repo_id,), r_filter, error_callback, *calbackdata)

def write_stignore(self, repo_id, text, callback, error_callback=None, *calbackdata):
"""
Asynchronously POSTs .stignore to daemon. Calls callback()
with on success, error_callback(exception) on failure.
"""
data = { 'ignore': text.split("\n") }
self._rest_post("ignores?repo=%s" % (repo_id,), data, callback, error_callback, *calbackdata)

def restart(self):
"""
Expand Down
85 changes: 85 additions & 0 deletions syncthing_gtk/ignoreeditor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env python2
"""
Syncthing-GTK - Ignore Pattern Editor
"""

from __future__ import unicode_literals
from gi.repository import Gtk, Gdk, Gio, GLib
from syncthing_gtk import DEBUG
import os, sys, re
_ = lambda (a) : a

class IgnoreEditor(object):
""" Standard looking about dialog """
def __init__(self, app, rid, file_location):
# Store stuff
self.app = app
self.rid = rid
self.file_location = file_location
# Load UI
self.setup_widgets()


def __getitem__(self, name):
""" Convince method that allows widgets to be accessed via self["widget"] """
return self.builder.get_object(name)

def show(self, parent=None):
if not parent is None:
self["dialog"].set_transient_for(parent)
self["dialog"].show_all()

def close(self, *a):
self["dialog"].set_visible(False)
self["dialog"].destroy()

def setup_widgets(self):
# Load glade file
self.builder = Gtk.Builder()
self.builder.add_from_file(os.path.join(self.app.gladepath, "ignore-editor.glade"))
self.builder.connect_signals(self)
self["lblLocation"].set_markup(
'%s <a href="file://%s">%s</a>' % (
_("File location:"),
os.path.join(os.path.expanduser(self.file_location), ".stignore"),
os.path.join(self.file_location, ".stignore")
)
)

def on_dialog_response(self, *a):
self.close()

def cb_btClose_clicked(self, *a):
self.close()

def on_lblLocation_activate_link(self, *a):
# Called when user clicks on file location link. Clicking there
# should open .stignore file in default text editor, allowing
# user to edit it there. Saving file from this dialog afterwards
# would overwrite his changes, so dialog closes itself to
# prevent that from happening
self.close()

def btSave_clicked_cb(self, *a):
start_iter = self["tbPatterns"].get_start_iter()
end_iter = self["tbPatterns"].get_end_iter()
text = self["tbPatterns"].get_text(start_iter, end_iter, True)
self["tvPatterns"].set_sensitive(False)
self["btSave"].set_sensitive(False)
# TODO: Expect error and create appropriate callback for it
self.app.daemon.write_stignore(self.rid, text, self.close, self.close)

def load(self):
self.app.daemon.read_stignore(self.rid, self.cb_data_loaded, self.cb_data_failed)

def cb_data_failed(self, *a):
# This should be next to impossible, so simply closing dialog
# should be enought of "solution"
print >>sys.stderr, "Failed to load .stignore data:", a
self.close()

def cb_data_loaded(self, text):
self["tbPatterns"].set_text(text)
self["tvPatterns"].grab_focus()
self["tvPatterns"].set_sensitive(True)
self["btSave"].set_sensitive(True)

0 comments on commit 20f232e

Please sign in to comment.