gajim-plural/gajim/gtk/history_sync.py

305 lines
10 KiB
Python

# Copyright (C) 2017 Philipp Hörist <philipp AT hoerist.com>
#
# This file is part of Gajim.
#
# Gajim is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published
# by the Free Software Foundation; version 3 only.
#
# Gajim is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
import logging
from enum import IntEnum
from datetime import datetime, timedelta
from gi.repository import Gtk, GLib
from gajim.common import app
from gajim.common import ged
from gajim.common.const import ArchiveState
from gajim.gtk.util import load_icon
log = logging.getLogger('gajim.c.message_archiving')
class Pages(IntEnum):
TIME = 0
SYNC = 1
SUMMARY = 2
class HistorySyncAssistant(Gtk.Assistant):
def __init__(self, account, parent):
Gtk.Assistant.__init__(self)
# self.set_title(_('Synchronise History'))
self.set_resizable(False)
self.set_default_size(300, -1)
self.set_name('HistorySyncAssistant')
self.set_transient_for(parent)
self.account = account
self.con = app.connections[self.account]
self.timedelta = None
self.now = datetime.utcnow()
self.query_id = None
self.start = None
self.end = None
self.next = None
self.hide_buttons()
own_jid = self.con.get_own_jid().getStripped()
mam_start = ArchiveState.NEVER
archive = app.logger.get_archive_timestamp(own_jid)
if archive is not None and archive.oldest_mam_timestamp is not None:
mam_start = int(float(archive.oldest_mam_timestamp))
if mam_start == ArchiveState.NEVER:
self.current_start = self.now
elif mam_start == ArchiveState.ALL:
self.current_start = datetime.utcfromtimestamp(0)
else:
self.current_start = datetime.fromtimestamp(mam_start)
self.select_time = SelectTimePage(self)
self.append_page(self.select_time)
self.set_page_type(self.select_time, Gtk.AssistantPageType.INTRO)
self.download_history = DownloadHistoryPage(self)
self.append_page(self.download_history)
self.set_page_type(self.download_history,
Gtk.AssistantPageType.PROGRESS)
self.set_page_complete(self.download_history, True)
self.summary = SummaryPage(self)
self.append_page(self.summary)
self.set_page_type(self.summary, Gtk.AssistantPageType.SUMMARY)
self.set_page_complete(self.summary, True)
app.ged.register_event_handler('archiving-count-received',
ged.GUI1,
self._received_count)
app.ged.register_event_handler('archiving-interval-finished',
ged.GUI1,
self._received_finished)
app.ged.register_event_handler('raw-mam-message-received',
ged.PRECORE,
self._nec_mam_message_received)
self.connect('prepare', self.on_page_change)
self.connect('destroy', self.on_destroy)
self.connect("cancel", self.on_close_clicked)
self.connect("close", self.on_close_clicked)
if mam_start == ArchiveState.ALL:
self.set_current_page(Pages.SUMMARY)
self.summary.nothing_to_do()
self.show_all()
def hide_buttons(self):
'''
Hide some of the standard buttons that are included in Gtk.Assistant
'''
if self.get_property('use-header-bar'):
action_area = self.get_children()[1]
else:
box = self.get_children()[0]
content_box = box.get_children()[1]
action_area = content_box.get_children()[1]
for button in action_area.get_children():
button_name = Gtk.Buildable.get_name(button)
if button_name == 'back':
button.connect('show', self._on_show_button)
elif button_name == 'forward':
self.next = button
button.connect('show', self._on_show_button)
@staticmethod
def _on_show_button(button):
button.hide()
def prepare_query(self):
if self.timedelta:
self.start = self.now - self.timedelta
self.end = self.current_start
log.info('get mam_start_date: %s', self.current_start)
log.info('now: %s', self.now)
log.info('start: %s', self.start)
log.info('end: %s', self.end)
self.query_id = self.con.get_module('MAM').request_archive_count(
self.start, self.end)
def _received_count(self, event):
if event.query_id != self.query_id:
return
if event.count is not None:
self.download_history.count = int(event.count)
self.query_id = self.con.get_module('MAM').request_archive_interval(
self.start, self.end)
def _received_finished(self, event):
if event.query_id != self.query_id:
return
self.query_id = None
log.info('query finished')
GLib.idle_add(self.download_history.finished)
self.set_current_page(Pages.SUMMARY)
self.summary.finished()
def _nec_mam_message_received(self, event):
if event.conn.name != self.account:
return
result = event.stanza.getTag('result')
queryid = result.getAttr('queryid')
if queryid != self.query_id:
return
log.debug('received message')
GLib.idle_add(self.download_history.set_fraction)
def on_row_selected(self, listbox, row):
self.timedelta = row.get_child().get_delta()
if row:
self.set_page_complete(self.select_time, True)
else:
self.set_page_complete(self.select_time, False)
def on_page_change(self, assistant, page):
if page == self.download_history:
self.next.hide()
self.prepare_query()
def on_destroy(self, *args):
app.ged.remove_event_handler('archiving-count-received',
ged.GUI1,
self._received_count)
app.ged.remove_event_handler('archiving-interval-finished',
ged.GUI1,
self._received_finished)
app.ged.remove_event_handler('raw-mam-message-received',
ged.PRECORE,
self._nec_mam_message_received)
del app.interface.instances[self.account]['history_sync']
def on_close_clicked(self, *args):
self.destroy()
class SelectTimePage(Gtk.Box):
def __init__(self, assistant):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.set_spacing(18)
self.assistant = assistant
label = Gtk.Label(label=_('How far back do you want to go?'))
listbox = Gtk.ListBox()
listbox.set_hexpand(False)
listbox.set_halign(Gtk.Align.CENTER)
listbox.add(TimeOption(_('One Month'), 1))
listbox.add(TimeOption(_('Three Months'), 3))
listbox.add(TimeOption(_('One Year'), 12))
listbox.add(TimeOption(_('Everything')))
listbox.connect('row-selected', assistant.on_row_selected)
for row in listbox.get_children():
option = row.get_child()
if not option.get_delta():
continue
if assistant.now - option.get_delta() > assistant.current_start:
row.set_activatable(False)
row.set_selectable(False)
self.pack_start(label, True, True, 0)
self.pack_start(listbox, False, False, 0)
class DownloadHistoryPage(Gtk.Box):
def __init__(self, assistant):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.set_spacing(18)
self.assistant = assistant
self.count = 0
self.received = 0
surface = load_icon('folder-download-symbolic', self, size=64)
image = Gtk.Image.new_from_surface(surface)
self.progress = Gtk.ProgressBar()
self.progress.set_show_text(True)
self.progress.set_text(_('Connecting...'))
self.progress.set_pulse_step(0.1)
self.progress.set_vexpand(True)
self.progress.set_valign(Gtk.Align.CENTER)
self.pack_start(image, False, False, 0)
self.pack_start(self.progress, False, False, 0)
def set_fraction(self):
self.received += 1
if self.count:
self.progress.set_fraction(self.received / self.count)
self.progress.set_text(_('%(received)s of %(max)s' % {
'received': self.received, 'max': self.count}))
else:
self.progress.pulse()
self.progress.set_text(_('Downloaded %s Messages' % self.received))
def finished(self):
self.progress.set_fraction(1)
class SummaryPage(Gtk.Box):
def __init__(self, assistant):
super().__init__(orientation=Gtk.Orientation.VERTICAL)
self.set_spacing(18)
self.assistant = assistant
self.label = Gtk.Label()
self.label.set_name('FinishedLabel')
self.label.set_valign(Gtk.Align.CENTER)
self.pack_start(self.label, True, True, 0)
def finished(self):
received = self.assistant.download_history.received
finished = _('''
Finished synchronising your History.
{received} Messages downloaded.
'''.format(received=received))
self.label.set_text(finished)
def nothing_to_do(self):
nothing_to_do = _('''
Gajim is fully synchronised
with the Archive.
''')
self.label.set_text(nothing_to_do)
def query_already_running(self):
already_running = _('''
There is already a synchronisation in
progress. Please try later.
''')
self.label.set_text(already_running)
class TimeOption(Gtk.Label):
def __init__(self, label, months=None):
super().__init__(label=label)
self.date = months
if months:
self.date = timedelta(days=30 * months)
def get_delta(self):
return self.date