示例#1
0
	def error(self, page, title, message, display_bugreport_link):
		"""
		Called from pages on error. Removes everything from page and
		creates error message.
		"""
		for c in [] + page.get_children() :
			page.remove(c)
		# Title
		l_title = WrappedLabel("<b>%s</b>" % (title,))
		l_title.props.margin_bottom = 15
		page.attach(l_title,	0, 0, 2, 1)
		# Message
		l_message = WrappedLabel(message)
		l_message.props.margin_bottom = 15
		page.attach(l_message,	0, 1, 2, 1)
		# Bugreport link
		if display_bugreport_link:
			github_link = '<a href="https://github.com/syncthing/syncthing-gtk/issues">GitHub</a>'
			l_bugreport = WrappedLabel(
				_("Please, check error log and fill bug report on %s.") % (github_link,)
			)
			page.attach(l_bugreport, 0, 2, 2, 1)
			# 'Display error log' button
			button = Gtk.Button(_("Display error log"))
			button.props.margin_top = 25
			page.attach(button, 1, 3, 2, 1)
			button.connect("clicked", lambda *a : self.show_output())
		
		page.show_all()
		return page
示例#2
0
		def display(self):
			if len(self.updated) == 1 and len(self.deleted) == 0:
				# One updated file
				f_path = list(self.updated)[0]
				filename = os.path.split(f_path)[-1]
				self.info(_("The file '%s' was updated on remote device.") % (filename,))
			elif len(self.updated) == 0 and len(self.deleted) == 1:
				# One deleted file
				f_path = list(self.deleted)[0]
				filename = os.path.split(f_path)[-1]
				self.info(_("The file '%s' was deleted on remote device.") % (filename,))
			elif len(self.deleted) == 0 and len(self.updated) > 0:
				# Multiple updated, nothing deleted
				self.info(_("%s files were updated on remote device.") % (len(self.updated),))
			elif len(self.updated) == 0 and len(self.deleted) > 0:
				# Multiple deleted, no updated
				self.info(_("%s files were deleted on remote device.") % (len(self.deleted),))
			elif len(self.deleted) > 0 and len(self.updated) > 0:
				 # Multiple deleted, multiple updated
				self.info(
					_("%(updated)s files were updated and %(deleted)s deleted on remote device.") % {
						'updated' : len(self.updated),
						'deleted' : len(self.deleted)
						}
					)
			self.updated = set([])
			self.deleted = set([])
示例#3
0
 def init_page(self):
     """ Displayed while Syncthing binary is being searched for """
     self.label = WrappedLabel(
         "<b>%s</b>\n\n%s" %
         (_("Syncthing is generating RSA key and certificate."),
          _("This may take a while...")))
     self.attach(self.label, 0, 0, 1, 1)
示例#4
0
	def cb_process_exit(self, process, *a):
		""" Called after daemon binary outputs version and exits """
		from syncthing_gtk.app import MIN_ST_VERSION
		bin_path = process.get_commandline()[0]
		if compare_version(self.version_string, MIN_ST_VERSION):
			# Daemon binary exists, is executable and meets
			# version requirements. That's good, btw.
			self.parent.config["syncthing_binary"] = bin_path
			if not can_upgrade_binary(bin_path):
				# Don't try enable auto-update if binary is in
				# non-writable location (auto-update is enabled
				# by default on Windows only)
				self.parent.config["st_autoupdate"] = False
			self.parent.set_page_complete(self, True)
			self.label.set_markup(
					"<b>" + _("Syncthing daemon binary found.") + "</b>" +
					"\n\n" +
					_("Binary path:") + " " + bin_path + "\n" +
					_("Version:") + " " + self.version_string
				)
		else:
			# Found daemon binary too old to be ussable.
			# Just ignore it and try to find better one.
			log.info("Binary in %s is too old", bin_path)
			self.ignored_version = self.version_string
			GLib.idle_add(self.search)
示例#5
0
		def display(self):
			if len(self.updated) == 1 and len(self.deleted) == 0:
				# One updated file
				f_path = list(self.updated)[0]
				filename = os.path.split(f_path)[-1]
				self.info(_("The file '%s' was updated on remote device.") % (filename,))
			elif len(self.updated) == 0 and len(self.deleted) == 1:
				# One deleted file
				f_path = list(self.deleted)[0]
				filename = os.path.split(f_path)[-1]
				self.info(_("The file '%s' was deleted on remote device.") % (filename,))
			elif len(self.deleted) == 0 and len(self.updated) > 0:
				# Multiple updated, nothing deleted
				self.info(_("%s files were updated on remote device.") % (len(self.updated),))
			elif len(self.updated) == 0 and len(self.deleted) > 0:
				# Multiple deleted, no updated
				self.info(_("%s files were deleted on remote device.") % (len(self.deleted),))
			elif len(self.deleted) > 0 and len(self.updated) > 0:
				 # Multiple deleted, multiple updated
				self.info(
					_("%(updated)s files were updated and %(deleted)s deleted on remote device.") % {
						'updated' : len(self.updated),
						'deleted' : len(self.deleted)
						}
					)
			self.updated = set([])
			self.deleted = set([])
示例#6
0
 def init_page(self):
     """ Displayed while settings are being saved """
     self.label = WrappedLabel("<b>" + _("Saving settings...") + "</b>" +
                               "\n\n")
     self.status = Gtk.Label(_("Checking for available port..."))
     self.attach(self.label, 0, 0, 1, 1)
     self.attach(self.status, 0, 1, 1, 1)
示例#7
0
        def rejected(self, nid):
            device = self.app.devices[nid].get_title()
            label_fb = self.label or self.id
            actions = [
                (self.ACT_DEFAULT, _('Accept folder "%s"') % label_fb,
                 self.cb_accept, nid),
                (self.ACT_ACCEPT, _('Accept folder "%s"') % label_fb,
                 self.cb_accept, nid),
                (self.ACT_IGNORE, _('Ignore folder "%s"') % label_fb,
                 self.cb_ignore, nid),
            ]

            markup_dev = self.supports("body-markup", "<b>%s</b>" % device,
                                       device)
            markup_fol = self.supports("body-markup", "<b>%s</b>" % label_fb,
                                       label_fb)

            summary = _("Folder rejected")
            body = _(
                'Unexpected folder "%(folder)s" sent from device "%(device)s".'
            ) % {
                'device': markup_dev,
                'folder': markup_fol
            }
            self.push(summary,
                      body,
                      actions=actions,
                      urg=Notify.Urgency.CRITICAL)
示例#8
0
	def prepare(self):
		# Determine which Syncthing to use
		suffix, tag = StDownloader.determine_platform()
		# Report error on unsupported platforms
		if suffix is None or tag is None:
			pd = "%s %s %s" % (
				platform.uname()[0], platform.uname()[2],	# OS, version
				platform.uname()[4])						# architecture
			self.parent.error(self,
				_("Cannot download Syncthing daemon."),
				_("This platform (%s) is not supported") % (pd,),
				False)
			return
		# Determine target file & directory
		self.target = os.path.join(
			os.path.expanduser(StDownloader.get_target_folder()),
			"syncthing%s" % (suffix,)
			)
		# Create downloader and connect events
		self.sd = StDownloader(self.target, tag)
		self.sd.connect("error", self.on_download_error)
		self.sd.connect("version", self.on_version)
		self.sd.connect("download-progress", self.on_progress)
		self.sd.connect("download-finished", self.on_extract_start)
		self.sd.connect("extraction-progress", self.on_progress)
		self.sd.connect("extraction-finished", self.on_extract_finished)
		# Start downloading
		self.sd.get_version()
示例#9
0
    def error(self, page, title, message, display_bugreport_link):
        """
		Called from pages on error. Removes everything from page and
		creates error message.
		"""
        for c in [] + page.get_children():
            page.remove(c)
        # Title
        l_title = WrappedLabel("<b>%s</b>" % (title, ))
        l_title.props.margin_bottom = 15
        page.attach(l_title, 0, 0, 2, 1)
        # Message
        l_message = WrappedLabel(message)
        l_message.props.margin_bottom = 15
        page.attach(l_message, 0, 1, 2, 1)
        # Bugreport link
        if display_bugreport_link:
            github_link = '<a href="https://github.com/syncthing/syncthing-gtk/issues">GitHub</a>'
            l_bugreport = WrappedLabel(
                _("Please, check error log and fill bug report on %s.") %
                (github_link, ))
            page.attach(l_bugreport, 0, 2, 2, 1)
            # 'Display error log' button
            button = Gtk.Button(_("Display error log"))
            button.props.margin_top = 25
            page.attach(button, 1, 3, 2, 1)
            button.connect("clicked", lambda *a: self.show_output())

        page.show_all()
        return page
示例#10
0
	def cb_process_exit(self, process, *a):
		""" Called after daemon binary outputs version and exits """
		from syncthing_gtk.app import MIN_ST_VERSION
		bin_path = process.get_commandline()[0]
		if compare_version(self.version_string, MIN_ST_VERSION):
			# Daemon binary exists, is executable and meets
			# version requirements. That's good, btw.
			self.parent.config["syncthing_binary"] = bin_path
			if not can_upgrade_binary(bin_path):
				# Don't try enable auto-update if binary is in
				# non-writable location (auto-update is enabled
				# by default on Windows only)
				self.parent.config["st_autoupdate"] = False
			self.parent.set_page_complete(self, True)
			self.label.set_markup(
					"<b>" + _("Syncthing daemon binary found.") + "</b>" +
					"\n\n" +
					_("Binary path:") + " " + bin_path + "\n" +
					_("Version:") + " " + self.version_string
				)
		else:
			# Found daemon binary too old to be ussable.
			# Just ignore it and try to find better one.
			log.info("Binary in %s is too old", bin_path)
			self.ignored_version = self.version_string
			GLib.idle_add(self.search)
	def _open_achive(self, archive_name):
		try:
			# Determine archive format
			archive = None
			if tarfile.is_tarfile(archive_name):
				# Open TAR
				archive = tarfile.open(archive_name, "r", bufsize=CHUNK_SIZE * 2)
			elif zipfile.is_zipfile(archive_name):
				# Open ZIP
				archive = ZipThatPretendsToBeTar(archive_name, "r")
			else:
				# Unrecognized format
				self.emit("error", None, _("Downloaded file is corrupted."))
			# Find binary inside
			for pathname in archive.getnames():
				filename = pathname.replace("\\", "/").split("/")[-1]
				if filename.startswith("syncthing"):
					# Last sanity check, then just open files
					# and start extracting
					tinfo = archive.getmember(pathname)
					if tinfo.isfile():
						compressed = archive.extractfile(pathname)
						try:
							os.makedirs(os.path.split(self.target)[0])
						except Exception: pass
						output = file(self.target, "wb")
						GLib.idle_add(self._extract, (archive, compressed, output, 0, tinfo.size))
						return
		except Exception, e:
			log.exception(e)
			self.emit("error", e,
				_("Failed to determine latest Syncthing version."))
			return
示例#12
0
 def prepare(self):
     # Determine which Syncthing to use
     suffix, tag = StDownloader.determine_platform()
     # Report error on unsupported platforms
     if suffix is None or tag is None:
         pd = "%s %s %s" % (
             platform.uname()[0],
             platform.uname()[2],  # OS, version
             platform.uname()[4])  # architecture
         self.parent.error(
             self, _("Cannot download Syncthing daemon."),
             _("This platform (%s) is not supported") % (pd, ), False)
         return
     # Determine target file & directory
     self.target = os.path.join(
         os.path.expanduser(StDownloader.get_target_folder()),
         "syncthing%s" % (suffix, ))
     # Create downloader and connect events
     self.sd = StDownloader(self.target, tag)
     self.sd.connect("error", self.on_download_error)
     self.sd.connect("version", self.on_version)
     self.sd.connect("download-progress", self.on_progress)
     self.sd.connect("download-finished", self.on_extract_start)
     self.sd.connect("extraction-progress", self.on_progress)
     self.sd.connect("extraction-finished", self.on_extract_finished)
     # Start downloading
     self.sd.get_version()
示例#13
0
 def cb_format_value_s_or_disabed(self, spinner):
     """ Formats spinner value """
     val = int(spinner.get_adjustment().get_value())
     if val < 1:
         spinner.get_buffer().set_text(_("disabled"), -1)
     else:
         spinner.get_buffer().set_text(_("%ss") % (val, ), -1)
     return True
示例#14
0
 def on_extract_finished(self, *a):
     """ Called after extraction is finished """
     # Everything done. Praise supernatural entities...
     self.label.set_markup("<b>" + _("Download finished.") + "</b>")
     self.parent.config["syncthing_binary"] = self.target
     self.version.set_markup(_("Binary path:") + " " + self.target)
     self.pb.set_visible(False)
     self.parent.set_page_complete(self, True)
示例#15
0
	def cb_format_value_kibps_or_no_limit(self, spinner):
		""" Formats spinner value """
		val = int(spinner.get_adjustment().get_value())
		if val < 1:
			spinner.get_buffer().set_text(_("no limit"), -1)
		else:
			spinner.get_buffer().set_text(_("%s KiB/s") % (val,), -1)
		return True
	def cb_format_value_s_or_disabed(self, spinner):
		""" Formats spinner value """
		val = int(spinner.get_adjustment().get_value())
		if val < 1:
			spinner.get_buffer().set_text(_("disabled"), -1)
		else:
			spinner.get_buffer().set_text(_("%ss") % (val,), -1);
		return True
示例#17
0
 def cb_format_value_kibps_or_no_limit(self, spinner):
     """ Formats spinner value """
     val = int(spinner.get_adjustment().get_value())
     if val < 1:
         spinner.get_buffer().set_text(_("no limit"), -1)
     else:
         spinner.get_buffer().set_text(_("%s KiB/s") % (val, ), -1)
     return True
示例#18
0
	def init_page(self):
		""" Displayed while Syncthing binary is being searched for """
		self.label = WrappedLabel(
			"<b>%s</b>\n\n%s" % (
				_("Syncthing is generating RSA key and certificate."),
				_("This may take a while...")
			)
		)
		self.attach(self.label, 0, 0, 1, 1)
示例#19
0
 def init_page(self):
     """ Well, it's last page. """
     label = WrappedLabel(
         "<b>" + _("Done.") + "</b>" + "\n\n" +
         _("Syncthing has been successfully configured.") + "\n" +
         _("You can configure more details later, in "
           "<b>UI Settings</b> and <b>Daemon Settings</b> menus "
           "in main window of application."))
     self.attach(label, 0, 0, 1, 1)
示例#20
0
 def init_page(self):
     """ Displayed while Syncthing binary is being searched for """
     self.label = WrappedLabel("<b>" +
                               _("Searching for Syncthing daemon.") +
                               "</b>" + "\n\n" + _("Please wait..."))
     self.paths = []
     self.version_string = "v0.0"
     self.ignored_version = None
     self.attach(self.label, 0, 0, 1, 1)
示例#21
0
	def on_extract_finished(self, *a):
		""" Called after extraction is finished """
		# Everything done. Praise supernatural entities...
		self.label.set_markup("<b>" + _("Download finished.") + "</b>")
		self.parent.config["syncthing_binary"] = self.target
		self.version.set_markup(_("Binary path:") +
				" " + self.target)
		self.pb.set_visible(False)
		self.parent.set_page_complete(self, True)
示例#22
0
	def init_page(self):
		""" Displayed while wizard downloads and extracts daemon """
		self.label = WrappedLabel("<b>" + _("Downloading Syncthing daemon.") + "</b>")
		self.version = WrappedLabel(_("Please wait..."))
		self.pb = Gtk.ProgressBar()
		self.label.props.margin_bottom = 15
		self.target = None
		self.attach(self.label,		0, 0, 1, 1)
		self.attach(self.version,	0, 1, 1, 1)
		self.attach(self.pb,		0, 2, 1, 1)
示例#23
0
 def cb_format_value_days(self, spinner):
     """ Formats spinner value """
     v = int(spinner.get_adjustment().get_value())
     if v == 0:
         spinner.get_buffer().set_text(_("never delete"), -1)
     elif v == 1:
         spinner.get_buffer().set_text(_("%s day") % (v, ), -1)
     else:
         spinner.get_buffer().set_text(_("%s days") % (v, ), -1)
     return True
示例#24
0
	def init_page(self):
		""" Displayed while wizard downloads and extracts daemon """
		self.label = WrappedLabel("<b>" + _("Downloading Syncthing daemon.") + "</b>")
		self.version = WrappedLabel(_("Please wait..."))
		self.pb = Gtk.ProgressBar()
		self.label.props.margin_bottom = 15
		self.target = None
		self.attach(self.label,		0, 0, 1, 1)
		self.attach(self.version,	0, 1, 1, 1)
		self.attach(self.pb,		0, 2, 1, 1)
	def cb_format_value_days(self, spinner):
		""" Formats spinner value """
		v = int(spinner.get_adjustment().get_value())
		if v == 0:
			spinner.get_buffer().set_text(_("never delete"), -1)
		elif v == 1:
			spinner.get_buffer().set_text(_("%s day") % (v,), -1);
		else:
			spinner.get_buffer().set_text(_("%s days") % (v,), -1);
		return True
示例#26
0
		def rejected(self):
			label_fb = self.label or self.id
			actions = [
				(self.ACT_DEFAULT, _('Accept device "%s"') % label_fb, self.cb_accept, None),
				(self.ACT_ACCEPT,  _('Accept device "%s"') % label_fb, self.cb_accept, None),
				(self.ACT_IGNORE,  _('Ignore device "%s"') % label_fb, self.cb_ignore, None),
			]
			summary = _("Unknown Device")
			body = _('Device "%s" is trying to connect to syncthing daemon.' % self.label)
			self.push(summary, body, actions=actions, urg=Notify.Urgency.CRITICAL)
示例#27
0
	def init_page(self):
		""" Permits user to set WebUI settings """
		# Wall of text
		label = WrappedLabel(
			"<b>" + _("WebUI setup") + "</b>" +
			"\n\n" +
			_("Syncthing can be managed remotely using WebUI and "
			  "even if you are going to use Syncthing-GTK, WebUI needs "
			  "to be enabled, as Syncthing-GTK uses it to communicate "
			  "with the Syncthing daemon.") +
			"\n\n" +
			_("If you prefer to be able to manage Syncthing remotely, "
			  "over the internet or on your local network, select <b>listen "
			  "on all interfaces</b> and set username and password to "
			  "protect Syncthing from unauthorized access.") +
			"\n" +
			_("Otherwise, select <b>listen on localhost</b>, so only "
			  "users and programs on this computer will be able to "
			  "interact with Syncthing.") +
			"\n"
		)
		# Radiobuttons
		lbl_radios = WrappedLabel("<b>" + _("WebUI Listen Addresses") + "</b>")
		self.rb_localhost = Gtk.RadioButton(label=_("Listen on _localhost"))
		self.rb_all_intfs = Gtk.RadioButton.new_from_widget(self.rb_localhost)
		self.rb_all_intfs.set_label(_("Listen on _all interfaces"))
		for x in (self.rb_localhost, self.rb_all_intfs):
			x.set_use_underline(True)
			x.set_property('margin-left', 15)
		# Username & password input boxes
		self.tx_username = Gtk.Entry()
		self.tx_password = Gtk.Entry()
		self.lbl_username = WrappedLabel(_("_Username"))
		self.lbl_password = WrappedLabel(_("_Password"))
		self.lbl_username.set_mnemonic_widget(self.tx_username)
		self.lbl_password.set_mnemonic_widget(self.tx_password)
		self.tx_password.set_visibility(False)
		self.tx_password.props.caps_lock_warning = True
		for x in (self.lbl_username, self.lbl_password):
			x.set_use_underline(True)
			x.set_property('margin-left', 45)
			x.set_property('margin-bottom', 5)
		for x in (self.tx_username, self.tx_password):
			x.set_property('margin-bottom', 5)
		# Connect signals
		for x in (self.rb_localhost, self.rb_all_intfs):
			x.connect("toggled", self.cb_stuff_changed)
		for x in (self.tx_username, self.tx_password):
			x.connect("changed", self.cb_stuff_changed)
			x.connect("delete-text", self.cb_stuff_changed)
			x.connect("insert-text", self.cb_stuff_changed)
		# Attach everything
		self.attach(label, 0, 0, 3, 1)
		self.attach(lbl_radios, 0, 1, 3, 1)
		self.attach(self.rb_localhost, 0, 2, 2, 1)
		self.attach(self.rb_all_intfs, 0, 3, 2, 1)
		self.attach(self.lbl_username, 0, 4, 1, 1)
		self.attach(self.lbl_password, 0, 5, 1, 1)
		self.attach(self.tx_username, 1, 4, 2, 1)
		self.attach(self.tx_password, 1, 5, 2, 1)
示例#28
0
	def init_page(self):
		""" Permits user to set WebUI settings """
		# Wall of text
		label = WrappedLabel(
			"<b>" + _("WebUI setup") + "</b>" +
			"\n\n" +
			_("Syncthing can be managed remotely using WebUI and "
			  "even if you are going to use Syncthing-GTK, WebUI needs "
			  "to be enabled, as Syncthing-GTK uses it to communicate "
			  "with the Syncthing daemon.") +
			"\n\n" +
			_("If you prefer to be able to manage Syncthing remotely, "
			  "over the internet or on your local network, select <b>listen "
			  "on all interfaces</b> and set username and password to "
			  "protect Syncthing from unauthorized access.") +
			"\n" +
			_("Otherwise, select <b>listen on localhost</b>, so only "
			  "users and programs on this computer will be able to "
			  "interact with Syncthing.") +
			"\n"
		)
		# Radiobuttons
		lbl_radios = WrappedLabel("<b>" + _("WebUI Listen Addresses") + "</b>")
		self.rb_localhost = Gtk.RadioButton(label=_("Listen on _localhost"))
		self.rb_all_intfs = Gtk.RadioButton.new_from_widget(self.rb_localhost)
		self.rb_all_intfs.set_label(_("Listen on _all interfaces"))
		for x in (self.rb_localhost, self.rb_all_intfs):
			x.set_use_underline(True)
			x.set_property('margin-left', 15)
		# Username & password input boxes
		self.tx_username = Gtk.Entry()
		self.tx_password = Gtk.Entry()
		self.lbl_username = WrappedLabel(_("_Username"))
		self.lbl_password = WrappedLabel(_("_Password"))
		self.lbl_username.set_mnemonic_widget(self.tx_username)
		self.lbl_password.set_mnemonic_widget(self.tx_password)
		self.tx_password.set_visibility(False)
		self.tx_password.props.caps_lock_warning = True
		for x in (self.lbl_username, self.lbl_password):
			x.set_use_underline(True)
			x.set_property('margin-left', 45)
			x.set_property('margin-bottom', 5)
		for x in (self.tx_username, self.tx_password):
			x.set_property('margin-bottom', 5)
		# Connect signals
		for x in (self.rb_localhost, self.rb_all_intfs):
			x.connect("toggled", self.cb_stuff_changed)
		for x in (self.tx_username, self.tx_password):
			x.connect("changed", self.cb_stuff_changed)
			x.connect("delete-text", self.cb_stuff_changed)
			x.connect("insert-text", self.cb_stuff_changed)
		# Attach everything
		self.attach(label, 0, 0, 3, 1)
		self.attach(lbl_radios, 0, 1, 3, 1)
		self.attach(self.rb_localhost, 0, 2, 2, 1)
		self.attach(self.rb_all_intfs, 0, 3, 2, 1)
		self.attach(self.lbl_username, 0, 4, 1, 1)
		self.attach(self.lbl_password, 0, 5, 1, 1)
		self.attach(self.tx_username, 1, 4, 2, 1)
		self.attach(self.tx_password, 1, 5, 2, 1)
示例#29
0
	def init_page(self):
		""" Displayed while Syncthing binary is being searched for """
		self.label = WrappedLabel(
			"<b>" + _("Searching for Syncthing daemon.") + "</b>" +
			"\n\n" +
			_("Please wait...")
		)
		self.paths = []
		self.version_string = "v0.0"
		self.ignored_version = None
		self.attach(self.label, 0, 0, 1, 1)
示例#30
0
	def cb_daemon_exit(self, dproc, exit_code):
		""" Called when Syncthing finishes """
		if exit_code == 0:
			# Finished without problem, advance to next page
			self.parent.set_page_complete(self, True)
			self.parent.next_page()
		else:
			self.parent.error(self,
				_("Failed to generate keys"),
				_("Syncthing daemon failed to generate RSA key or certificate."),
				True)
示例#31
0
 def cb_daemon_exit(self, dproc, exit_code):
     """ Called when Syncthing finishes """
     if exit_code == 0:
         # Finished without problem, advance to next page
         self.parent.set_page_complete(self, True)
         self.parent.next_page()
     else:
         self.parent.error(
             self, _("Failed to generate keys"),
             _("Syncthing daemon failed to generate RSA key or certificate."
               ), True)
示例#32
0
	def init_page(self):
		""" Well, it's last page. """
		label = WrappedLabel(
			"<b>" + _("Done.") + "</b>" +
			"\n\n" +
			_("Syncthing has been successfully configured.") +
			"\n" +
			_("You can configure more details later, in "
			  "<b>UI Settings</b> and <b>Daemon Settings</b> menus "
			  "in main window of application.")
		)
		self.attach(label, 0, 0, 1, 1)
示例#33
0
		def sync_conflict(self, path):
			path_full = os.path.join(self.app.folders[self.id]["norm_path"], path)

			summary = _('Conflicting file in "%s"') % (self.label or self.id)
			text = _('Conflict in path "%s" detected.') % path_full

			n = Notify.Notification.new(summary, text, ICON_ERR)
			n.set_urgency(Notify.Urgency.CRITICAL)
			n.add_action(self.ACT_DEFAULT, _("Open Conflicting file in filemanager"), self.cb_open_conflict, path_full)
			n.connect("closed", self.cb_sync_conflict_closed),
			self.conflict.add(n)

			self.show(n)
示例#34
0
 def display(self):
     if len(self.updated) == 1 and len(self.deleted) == 0:
         # One updated file
         f_path = list(self.updated)[0]
         filename = os.path.split(f_path)[-1]
         self.info(
             _("%(hostname)s: Downloaded '%(filename)s' to reflect remote changes."
               ) % {
                   'hostname':
                   self.app.get_local_name(),
                   'filename':
                   "<a href='file://%s'>%s</a>" %
                   (f_path.encode('unicode-escape'), filename)
               })
     elif len(self.updated) == 0 and len(self.deleted) == 1:
         # One deleted file
         f_path = list(self.deleted)[0]
         filename = os.path.split(f_path)[-1]
         self.info(
             _("%(hostname)s: Deleted '%(filename)s' to reflect remote changes."
               ) % {
                   'hostname': self.app.get_local_name(),
                   'filename': filename
               })
     elif len(self.deleted) == 0 and len(self.updated) > 0:
         # Multiple updated, nothing deleted
         self.info(
             _("%(hostname)s: Downloaded %(updated)s files to reflect remote changes."
               ) % {
                   'hostname': self.app.get_local_name(),
                   'updated': len(self.updated)
               })
     elif len(self.updated) == 0 and len(self.deleted) > 0:
         # Multiple deleted, no updated
         self.info(
             _("%(hostname)s: Deleted %(deleted)s files to reflect remote changes."
               ) % {
                   'hostname': self.app.get_local_name(),
                   'deleted': len(self.deleted)
               })
     elif len(self.deleted) > 0 and len(self.updated) > 0:
         # Multiple deleted, multiple updated
         self.info(
             _("%(hostname)s: downloaded %(updated)s files and deleted %(deleted)s files to reflect remote changes."
               ) % {
                   'hostname': self.app.get_local_name(),
                   'updated': len(self.updated),
                   'deleted': len(self.deleted)
               })
     self.updated = set([])
     self.deleted = set([])
示例#35
0
	def init_page(self):
		""" First, intro page. Just static text that explains what's going on """ 
		config_folder = "~/.config/syncthing"
		config_folder_link = '<a href="file://%s">%s</a>' % (
				os.path.expanduser(config_folder), config_folder)
		self.attach(WrappedLabel(
			"<b>" + _("Welcome to Syncthing-GTK first run wizard!") + "</b>" +
			"\n\n" +
			_("It looks like you never have used Syncthing.") + " " +
			_("Initial configuration should be created.") +  " " +
			_("Please click <b>Next</b> to create a Syncthing configuration file or <b>Quit</b> to exit") +
			"\n\n" +
			(_("If you already had Syncthing daemon configured, please, "
			  "exit this wizard and check your %s folder") % config_folder_link )
		), 0, 0, 1, 1)
示例#36
0
    def cb_data_failed(self, exception, *a):
        """
		Failed to load configuration. This shouldn't happen unless daemon
		dies exactly when user clicks to edit menu.
		Handled by simple error message.
		"""
        # All other errors are fatal for now. Error dialog is displayed and program exits.
        d = Gtk.MessageDialog(
            self["editor"],
            Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, "%s %s\n\n%s %s" %
            (_("Failed to load configuration from daemon."), _("Try again."),
             _("Error message:"), str(exception)))
        d.run()
        self.close()
示例#37
0
	def __init__(self, app, title, icon):
		# Variables
		self.app = app
		self.child = None
		self.header = None
		self.str_title = None
		self.str_status = None
		self.header_inverted = False
		self.values = {}
		self.icons = {}
		self.value_widgets = {}
		self.hilight = False
		self.hilight_factor = 0.0
		self.timer_enabled = False
		self.icon = icon
		self.color = (1, 0, 1, 1)		# rgba
		self.background = (1, 1, 1, 1)	# rgba
		self.dark_color  = None			# Overrides background if set
		self.text_color = (0, 0, 0, 1)	# rgba (text color)
		self.real_color = self.color	# set color + hilight
		self.border_width = 2
		self.children = [self.header, self.child]
		# Initialization
		Gtk.Container.__init__(self)
		self.init_header()
		self.init_grid()
		# Settings
		self.set_title(title)
		self.set_status(_("Disconnected"))
示例#38
0
	def add_page(self, page):
		""" Adds page derived from custom Page class """
		index = self.append_page(page)
		page.parent = self
		self.set_page_type(page, page.TYPE)
		self.set_page_title(page, _(page.TITLE) + "  ")
		return index
示例#39
0
 def init_page(self):
     """ First, intro page. Just static text that explains what's going on """
     config_folder = "~/.config/syncthing"
     config_folder_link = '<a href="file://%s">%s</a>' % (
         os.path.expanduser(config_folder), config_folder)
     self.attach(
         WrappedLabel(
             "<b>" + _("Welcome to Syncthing-GTK first run wizard!") +
             "</b>" + "\n\n" +
             _("It looks like you never have used Syncthing.") + " " +
             _("Initial configuration should be created.") + " " +
             _("Please click <b>Next</b> to create a Syncthing configuration file or <b>Quit</b> to exit"
               ) + "\n\n" +
             (_("If you already had Syncthing daemon configured, please, "
                "exit this wizard and check your %s folder") %
              config_folder_link)), 0, 0, 1, 1)
示例#40
0
	def on_btBrowse_clicked(self, *a):
		"""
		Display folder browser dialog to browse for folder... folder.
		Oh god, this new terminology sucks...
		"""
		if not self.is_new: return
		# Prepare dialog
		d = Gtk.FileChooserDialog(
			_("Select Folder for new Folder"),	# f**k me...
			self["editor"],
			Gtk.FileChooserAction.SELECT_FOLDER,
			(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
			Gtk.STOCK_OK, Gtk.ResponseType.OK))
		# Set default path to home directory
		d.set_current_folder(os.path.expanduser("~"))
		# Get response
		if d.run() == Gtk.ResponseType.OK:
			self["vpath"].set_text(d.get_filename())
			if len(self["vid"].get_text().strip()) == 0:
				# ID is empty, fill it with last path element
				try:
					lpl = os.path.split(d.get_filename())[-1]
					id = RE_GEN_ID.search(lpl).group(0).lower()
					self["vid"].set_text(id)
				except AttributeError:
					# Can't regexp anything
					pass
		d.destroy()
示例#41
0
	def _cb_read_latest(self, f, result, buffer, *a):
		# Extract release version from response
		from syncthing_gtk.app import MIN_ST_VERSION
		latest_ver = None
		try:
			success, data, etag = f.load_contents_finish(result)
			if not success: raise Exception("Gio download failed")
			# Go over all available versions until compatibile one
			# is found
			data = json.loads(data)
			for release in data:
				version = release["tag_name"]
				if latest_ver is None:
					latest_ver = version
				if compare_version(self.latest_compat, version) and (self.forced or compare_version(version, MIN_ST_VERSION)):
					# Compatibile
					log.verbose("STDownloader: Found compatibile Syncthing version: %s", version)
					self.version = version
					for asset in release["assets"]:
						if self.platform in asset["name"]:
							self.dll_url = asset["browser_download_url"]
							self.dll_size = int(asset["size"])
							log.debug("STDownloader: URL: %s", self.dll_url)
							break
					break
				else:
					log.verbose("STDownloader: Ignoring too new Syncthing version: %s", version)
			del f
			if self.dll_url is None:
				raise Exception("No release to download")
		except Exception, e:
			log.exception(e)
			self.emit("error", e,
				_("Failed to determine latest Syncthing version."))
			return
示例#42
0
 def cb_syncthing_folder_finished(self, daemon, folder_id):
     if folder_id in self.syncing:
         self.syncing.remove(folder_id)
         folder_label = self.app.folders[folder_id]["label"]
         markup = _("Synchronization of folder '%s' is completed.") % (
             (folder_label or folder_id), )
         self.info(markup)
示例#43
0
    def syncthing_cb_post_error(self, exception, *a):
        # TODO: Unified error message
        if isinstance(exception, ConnectionRestarted):
            # Should be ok, this restart is triggered
            # by App handler for 'config-saved' event.
            return self.syncthing_cb_post_config()
        message = "%s\n%s" % (_("Failed to save configuration."),
                              str(exception))

        if hasattr(exception, "full_response"):
            try:
                fr = unicode(exception.full_response)[0:1024]
            except UnicodeError:
                # ... localized error strings on windows are usually
                # in anything but unicode :(
                fr = str(repr(exception.full_response))[0:1024]
            message += "\n\n" + fr

        d = Gtk.MessageDialog(
            self["editor"],
            Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, message)
        d.run()
        d.hide()
        d.destroy()
        self["editor"].set_sensitive(True)
示例#44
0
	def _extract(self, data):
		(archive, compressed, output, extracted, ex_size) = data
		try:
			buffer = compressed.read(CHUNK_SIZE)
			read_size = len(buffer)
			if read_size == CHUNK_SIZE:
				# Need some more
				output.write(buffer)
				extracted += read_size
				GLib.idle_add(self._extract, (archive, compressed, output, extracted, ex_size))
				self.emit("extraction-progress", float(extracted) / float(ex_size))
			else:
				# End of file
				# Write rest, if any
				if read_size > 0:
					output.write(buffer)
				# Change file mode to 0755
				if hasattr(os, "fchmod"):
					# ... on Unix
					os.fchmod(output.fileno(), 0o755)
				output.close()
				archive.close()
				compressed.close()
				self.emit("extraction-progress", 1.0)
				self.emit("extraction-finished")
		except Exception as e:
			log.exception(e)
			self.emit("error", e,
				_("Failed to determine latest Syncthing version."))
			return
		return False
示例#45
0
 def _cb_download(self, stream, result, data):
     (tmpfile, downloaded) = data
     try:
         # Get response from async call
         response = stream.read_bytes_finish(result)
         if response == None:
             raise Exception("No data received")
         # 0b of data read indicates end of file
         if response.get_size() > 0:
             # Not EOF. Write buffer to disk and download some more
             downloaded += response.get_size()
             tmpfile.write(response.get_data())
             stream.read_bytes_async(CHUNK_SIZE, GLib.PRIORITY_DEFAULT,
                                     None, self._cb_download,
                                     (tmpfile, downloaded))
             self.emit("download-progress",
                       float(downloaded) / float(self.dll_size))
         else:
             # EOF. Re-open tmpfile as tar and prepare to extract
             # binary
             self.emit("download-finished")
             stream.close(None)
             tmpfile.close()
             GLib.idle_add(self._open_archive, tmpfile.name)
     except Exception as e:
         log.exception(e)
         self.emit("error", e, _("Download failed."))
         return
示例#46
0
 def _extract(self, data):
     (archive, compressed, output, extracted, ex_size) = data
     try:
         buffer = compressed.read(CHUNK_SIZE)
         read_size = len(buffer)
         if read_size == CHUNK_SIZE:
             # Need some more
             output.write(buffer)
             extracted += read_size
             GLib.idle_add(
                 self._extract,
                 (archive, compressed, output, extracted, ex_size))
             self.emit("extraction-progress",
                       float(extracted) / float(ex_size))
         else:
             # End of file
             # Write rest, if any
             if read_size > 0:
                 output.write(buffer)
             # Change file mode to 0755
             if hasattr(os, "fchmod"):
                 # ... on Unix
                 os.fchmod(output.fileno(), 0o755)
             output.close()
             archive.close()
             compressed.close()
             self.emit("extraction-progress", 1.0)
             self.emit("extraction-finished")
     except Exception as e:
         log.exception(e)
         self.emit("error", e,
                   _("Failed to determine latest Syncthing version."))
         return
     return False
示例#47
0
	def syncthing_cb_post_error(self, exception, *a):
		# TODO: Unified error message
		if isinstance(exception, ConnectionRestarted):
			# Should be ok, this restart is triggered
			# by App handler for 'config-saved' event.
			return self.syncthing_cb_post_config()
		message = "%s\n%s" % (
			_("Failed to save configuration."),
			str(exception)
		)
		
		if hasattr(exception, "full_response"):
			try:
				fr = unicode(exception.full_response)[0:1024]
			except UnicodeError:
				# ... localized error strings on windows are usually
				# in anything but unicode :(
				fr = str(repr(exception.full_response))[0:1024]
			message += "\n\n" + fr
		
		d = Gtk.MessageDialog(
			self["editor"],
			Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
			Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
			message
			)
		d.run()
		d.hide()
		d.destroy()
		self["editor"].set_sensitive(True)
示例#48
0
	def __init__(self, app, title, icon):
		# Variables
		self.app = app
		self.child = None
		self.header = None
		self.str_title = None
		self.str_status = None
		self.header_inverted = False
		self.values = {}
		self.icons = {}
		self.value_widgets = {}
		self.hilight = False
		self.hilight_factor = 0.0
		self.timer_enabled = False
		self.icon = icon
		self.color = (1, 0, 1, 1)		# rgba
		self.background = (1, 1, 1, 1)	# rgba
		self.dark_color  = None			# Overrides background if set
		self.text_color = (0, 0, 0, 1)	# rgba (text color)
		self.real_color = self.color	# set color + hilight
		self.border_width = 2
		self.children = [self.header, self.child]
		# Initialization
		Gtk.Container.__init__(self)
		self.init_header()
		self.init_grid()
		# Settings
		self.set_title(title)
		self.set_status(_("Disconnected"))
示例#49
0
	def _cb_download(self, stream, result, data):
		(tmpfile, downloaded) = data
		try:
			# Get response from async call
			response = stream.read_bytes_finish(result)
			if response == None:
				raise Exception("No data received")
			# 0b of data read indicates end of file
			if response.get_size() > 0:
				# Not EOF. Write buffer to disk and download some more
				downloaded += response.get_size()
				tmpfile.write(response.get_data())
				stream.read_bytes_async(CHUNK_SIZE, GLib.PRIORITY_DEFAULT, None,
						self._cb_download, (tmpfile, downloaded))
				self.emit("download-progress", float(downloaded) / float(self.dll_size))
			else:
				# EOF. Re-open tmpfile as tar and prepare to extract
				# binary
				self.emit("download-finished")
				stream.close(None)
				tmpfile.close()
				GLib.idle_add(self._open_archive, tmpfile.name)
		except Exception as e:
			log.exception(e)
			self.emit("error", e, _("Download failed."))
			return
示例#50
0
    def on_btBrowse_clicked(self, *a):
        """
		Display folder browser dialog to browse for folder... folder.
		Oh god, this new terminology sucks...
		"""
        if not self.is_new: return
        # Prepare dialog
        d = Gtk.FileChooserDialog(
            _("Select Folder for new Folder"),  # f**k me...
            self["editor"],
            Gtk.FileChooserAction.SELECT_FOLDER,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK,
             Gtk.ResponseType.OK))
        # Set default path to home directory
        d.set_current_folder(os.path.expanduser("~"))
        # Get response
        if d.run() == Gtk.ResponseType.OK:
            self["vpath"].set_text(d.get_filename())
            if len(self["vid"].get_text().strip()) == 0:
                # ID is empty, fill it with last path element
                try:
                    lpl = os.path.split(d.get_filename())[-1]
                    id = RE_GEN_ID.search(lpl).group(0).lower()
                    self["vid"].set_text(id)
                except AttributeError:
                    # Can't regexp anything
                    pass
        d.destroy()
示例#51
0
 def add_page(self, page):
     """ Adds page derived from custom Page class """
     index = self.append_page(page)
     page.parent = self
     self.set_page_type(page, page.TYPE)
     self.set_page_title(page, _(page.TITLE) + "  ")
     return index
示例#52
0
	def cb_extract_finished(self, downloader, *a):
		""" Called after extraction is finished """
		self["vsyncthing_binary"].set_sensitive(True)
		self["btBrowse"].set_sensitive(True)
		self["vsyncthing_binary"].set_text(downloader.get_target())
		self["lblDownloadProgress"].set_markup("<b>" + _("Download finished.") + "</b>")
		self["pbDownload"].set_visible(False)
		self["btSave"].set_sensitive(True)
示例#53
0
    def cb_data_failed(self, exception, *a):
        """
		Failed to load configuration. This shouldn't happen unless daemon
		dies exactly when user clicks to edit menu.
		Handled by simple error message.
		"""
        # All other errors are fatal for now. Error dialog is displayed and program exits.
        d = Gtk.MessageDialog(
            self["editor"],
            Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
            Gtk.MessageType.ERROR,
            Gtk.ButtonsType.CLOSE,
            "%s %s\n\n%s %s"
            % (_("Failed to load configuration from daemon."), _("Try again."), _("Error message:"), str(exception)),
        )
        d.run()
        self.close()
	def cb_extract_finished(self, downloader, *a):
		""" Called after extraction is finished """
		self["vsyncthing_binary"].set_sensitive(True)
		self["btBrowse"].set_sensitive(True)
		self["vsyncthing_binary"].set_text(downloader.get_target())
		self["lblDownloadProgress"].set_markup("<b>" + _("Download finished.") + "</b>")
		self["pbDownload"].set_visible(False)
		self["btSave"].set_sensitive(True)
示例#55
0
 def __init__(self,
              gladepath="/usr/share/syncthing-gtk",
              iconpath="/usr/share/syncthing-gtk/icons",
              config=None):
     # Init
     Gtk.Assistant.__init__(self)
     if not config is None:
         self.config = config
     else:
         self.config = Configuration()
     self.gladepath = gladepath
     self.iconpath = iconpath
     self.syncthing_options = {}
     self.lines = []  # Daemon and wizard output,
     # maybe for error reports
     self.finished = False
     self.connect("prepare", self.prepare_page)
     # Find syncthing configuration directory
     self.st_configdir = os.path.join(get_config_dir(), "syncthing")
     self.st_configfile = os.path.join(get_config_dir(), "syncthing",
                                       "config.xml")
     # Window setup
     self.set_position(Gtk.WindowPosition.CENTER)
     self.set_size_request(720, -1)
     self.set_default_size(720, 300)
     self.set_deletable(True)
     if IS_WINDOWS:
         self.set_icon_list([
             GdkPixbuf.Pixbuf.new_from_file(
                 "icons/32x32/apps/syncthing-gtk.png")
         ])
     else:
         self.set_icon_name("syncthing-gtk")
     self.set_title("%s %s" % (_("Syncthing-GTK"), _("First run wizard")))
     # Add "Quit" button
     self.quit_button = Gtk.Button.new_from_stock("gtk-quit")
     self.add_action_widget(self.quit_button)
     self.quit_button.set_visible(True)
     self.quit_button.connect("clicked", lambda *a: self.emit("cancel"))
     # Pages
     self.add_page(IntroPage(self))
     self.add_page(FindDaemonPage())
     self.add_page(GenerateKeysPage())
     self.add_page(HttpSettingsPage())
     self.add_page(SaveSettingsPage())
     self.add_page(LastPage())
示例#56
0
	def check_port(self, port):
		"""
		Tries to open TCP port to check it availability.
		It this fails, checks next ports, until MAX_PORT is reached.
		When MAX_PORT is reached, it's safe to assume that something
		completely wrong is happening and an error should be displayed.
		"""
		if port >= MAX_PORT:
			# Remove config.xml that I just created
			try:
				os.unlink(self.parent.st_configfile)
			except Exception, e:
				self.parent.output_line("syncthing-gtk: %s" % (str(e),))
			self.parent.error(self,
				_("Failed to find unused port for listening."),
				_("Please, check your firewall settings and try again."),
				False)
			return
示例#57
0
		def cb_syncthing_error(self, daemon, message):
			summary = _('An error occurred in Syncthing!')
			n = Notify.Notification.new(summary, None, ICON_ERR)
			n.set_urgency(Notify.Urgency.CRITICAL)

			try:
				n.show()
			except Exception:
				pass
示例#58
0
	def insert(self, page):
		"""
		Inserts new page after currently displayed.
		"""
		index = self.get_current_page()
		index = self.insert_page(page, index + 1)
		page.parent = self
		self.set_page_type(page, page.TYPE)
		self.set_page_title(page, _(page.TITLE) + "  ")
		return index