* when in common, no need to do from common import FOO, just import FOO
* we now migrate automaticaly at startup in a thread * progressDialog now scroll textvew to the end
This commit is contained in:
parent
ed47580227
commit
637c903d68
8 changed files with 226 additions and 197 deletions
|
@ -20,7 +20,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import stat
|
import stat
|
||||||
|
|
||||||
import gajim
|
from common import gajim
|
||||||
import logger
|
import logger
|
||||||
import i18n
|
import i18n
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
import sre
|
import sre
|
||||||
import copy
|
import copy
|
||||||
from common import i18n
|
import i18n
|
||||||
_ = i18n._
|
_ = i18n._
|
||||||
|
|
||||||
OPT_TYPE = 0
|
OPT_TYPE = 0
|
||||||
|
|
|
@ -22,12 +22,12 @@ import sys
|
||||||
import logging
|
import logging
|
||||||
import mutex
|
import mutex
|
||||||
|
|
||||||
import common.config
|
import config
|
||||||
|
|
||||||
|
|
||||||
interface = None # The actual interface (the gtk one for the moment)
|
interface = None # The actual interface (the gtk one for the moment)
|
||||||
version = '0.9'
|
version = '0.9'
|
||||||
config = common.config.Config()
|
config = config.Config()
|
||||||
connections = {}
|
connections = {}
|
||||||
verbose = False
|
verbose = False
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ h.setFormatter(f)
|
||||||
log = logging.getLogger('Gajim')
|
log = logging.getLogger('Gajim')
|
||||||
log.addHandler(h)
|
log.addHandler(h)
|
||||||
|
|
||||||
import common.logger
|
import logger
|
||||||
logger = common.logger.Logger() # init the logger
|
logger = logger.Logger() # init the logger
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
if '.svn' in os.listdir('.') or '_svn' in os.listdir('.'):
|
if '.svn' in os.listdir('.') or '_svn' in os.listdir('.'):
|
||||||
|
|
|
@ -27,8 +27,8 @@ from pysqlite2 import dbapi2 as sqlite
|
||||||
|
|
||||||
import gajim
|
import gajim
|
||||||
import logger
|
import logger
|
||||||
from common import i18n
|
import i18n
|
||||||
from common.xmpp_stringprep import nodeprep, resourceprep, nameprep
|
from xmpp_stringprep import nodeprep, resourceprep, nameprep
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import winsound # windows-only built-in module for playing wav
|
import winsound # windows-only built-in module for playing wav
|
||||||
|
|
|
@ -22,8 +22,8 @@ import sys
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from common import exceptions
|
import exceptions
|
||||||
from common import i18n
|
import i18n
|
||||||
_ = i18n._
|
_ = i18n._
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -13,8 +13,6 @@ signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
|
||||||
|
|
||||||
from pysqlite2 import dbapi2 as sqlite
|
from pysqlite2 import dbapi2 as sqlite
|
||||||
|
|
||||||
constants = logger.Constants()
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
try:
|
try:
|
||||||
PATH_TO_LOGS_BASE_DIR = os.path.join(os.environ['appdata'], 'Gajim', 'Logs')
|
PATH_TO_LOGS_BASE_DIR = os.path.join(os.environ['appdata'], 'Gajim', 'Logs')
|
||||||
|
@ -25,46 +23,20 @@ if os.name == 'nt':
|
||||||
PATH_TO_DB = '../src/logs.db'
|
PATH_TO_DB = '../src/logs.db'
|
||||||
else:
|
else:
|
||||||
PATH_TO_LOGS_BASE_DIR = os.path.expanduser('~/.gajim/logs')
|
PATH_TO_LOGS_BASE_DIR = os.path.expanduser('~/.gajim/logs')
|
||||||
PATH_TO_DB = os.path.expanduser('~/.gajim/logs.db') # database is called logs.db
|
PATH_TO_DB = os.path.expanduser('~/.gajim/logs2.db') # database is called logs.db
|
||||||
|
|
||||||
if os.path.exists(PATH_TO_DB):
|
class migration:
|
||||||
|
def __init__(self):
|
||||||
|
self.constants = logger.Constants()
|
||||||
|
self.DONE = False
|
||||||
|
|
||||||
|
if os.path.exists(PATH_TO_DB):
|
||||||
print '%s already exists. Exiting..' % PATH_TO_DB
|
print '%s already exists. Exiting..' % PATH_TO_DB
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
jids_already_in = [] # jid we already put in DB
|
self.jids_already_in = [] # jid we already put in DB
|
||||||
con = sqlite.connect(PATH_TO_DB)
|
|
||||||
os.chmod(PATH_TO_DB, 0600) # rw only for us
|
|
||||||
cur = con.cursor()
|
|
||||||
# create the tables
|
|
||||||
# kind can be
|
|
||||||
# status, gcstatus, gc_msg, (we only recv for those 3),
|
|
||||||
# single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
|
|
||||||
# to meet all our needs
|
|
||||||
# logs.jid_id --> jids.jid_id but Sqlite doesn't do FK etc so it's done in python code
|
|
||||||
cur.executescript(
|
|
||||||
'''
|
|
||||||
CREATE TABLE jids(
|
|
||||||
jid_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
||||||
jid TEXT UNIQUE,
|
|
||||||
type INTEGER
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE logs(
|
def get_jid(self, dirname, filename):
|
||||||
log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
|
||||||
jid_id INTEGER,
|
|
||||||
contact_name TEXT,
|
|
||||||
time INTEGER,
|
|
||||||
kind INTEGER,
|
|
||||||
show INTEGER,
|
|
||||||
message TEXT,
|
|
||||||
subject TEXT
|
|
||||||
);
|
|
||||||
'''
|
|
||||||
)
|
|
||||||
|
|
||||||
con.commit()
|
|
||||||
|
|
||||||
def get_jid(dirname, filename):
|
|
||||||
# jids.jid text column will be JID if TC-related, room_jid if GC-related,
|
# jids.jid text column will be JID if TC-related, room_jid if GC-related,
|
||||||
# ROOM_JID/nick if pm-related. Here I get names from filenames
|
# ROOM_JID/nick if pm-related. Here I get names from filenames
|
||||||
if dirname.endswith('logs') or dirname.endswith('Logs'):
|
if dirname.endswith('logs') or dirname.endswith('Logs'):
|
||||||
|
@ -83,15 +55,18 @@ def get_jid(dirname, filename):
|
||||||
jid = jid.lower()
|
jid = jid.lower()
|
||||||
return jid
|
return jid
|
||||||
|
|
||||||
def decode_jid(string):
|
def decode_jid(self, string):
|
||||||
'''try to decode (to make it Unicode instance) given jid'''
|
'''try to decode (to make it Unicode instance) given jid'''
|
||||||
string = decode_string(string)
|
string = decode_string(string)
|
||||||
if isinstance(string, str):
|
if isinstance(string, str):
|
||||||
return None # decode failed
|
return None # decode failed
|
||||||
return string
|
return string
|
||||||
|
|
||||||
def visit(arg, dirname, filenames):
|
def visit(self, arg, dirname, filenames):
|
||||||
s = _('Visiting %s') % dirname
|
s = _('Visiting %s') % dirname
|
||||||
|
if self.queue:
|
||||||
|
self.queue.put(s)
|
||||||
|
else:
|
||||||
print s
|
print s
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
# Don't take this file into account, this is dup info
|
# Don't take this file into account, this is dup info
|
||||||
|
@ -102,21 +77,24 @@ def visit(arg, dirname, filenames):
|
||||||
if os.path.isdir(path_to_text_file):
|
if os.path.isdir(path_to_text_file):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
jid = get_jid(dirname, filename)
|
jid = self.get_jid(dirname, filename)
|
||||||
|
|
||||||
jid = decode_jid(jid)
|
jid = self.decode_jid(jid)
|
||||||
if not jid:
|
if not jid:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if filename == os.path.basename(dirname): # gajim@conf/gajim@conf then gajim@conf is type room
|
if filename == os.path.basename(dirname): # gajim@conf/gajim@conf then gajim@conf is type room
|
||||||
jid_type = constants.JID_ROOM_TYPE
|
jid_type = self.constants.JID_ROOM_TYPE
|
||||||
#Type of log
|
#Type of log
|
||||||
typ = 'room'
|
typ = 'room'
|
||||||
else:
|
else:
|
||||||
jid_type = constants.JID_NORMAL_TYPE
|
jid_type = self.constants.JID_NORMAL_TYPE
|
||||||
#Type of log
|
#Type of log
|
||||||
typ = _('normal')
|
typ = _('normal')
|
||||||
s = _('Processing %s of type %s') % (jid.encode('utf-8'), typ)
|
s = _('Processing %s of type %s') % (jid.encode('utf-8'), typ)
|
||||||
|
if self.queue:
|
||||||
|
self.queue.put(s)
|
||||||
|
else:
|
||||||
print s
|
print s
|
||||||
|
|
||||||
JID_ID = None
|
JID_ID = None
|
||||||
|
@ -150,20 +128,20 @@ def visit(arg, dirname, filenames):
|
||||||
if typ == 'gc':
|
if typ == 'gc':
|
||||||
contact_name = message_data[0]
|
contact_name = message_data[0]
|
||||||
message = ':'.join(message_data[1:])
|
message = ':'.join(message_data[1:])
|
||||||
kind = constants.KIND_GC_MSG
|
kind = self.constants.KIND_GC_MSG
|
||||||
elif typ == 'gcstatus':
|
elif typ == 'gcstatus':
|
||||||
contact_name = message_data[0]
|
contact_name = message_data[0]
|
||||||
show = message_data[1]
|
show = message_data[1]
|
||||||
message = ':'.join(message_data[2:]) # status msg
|
message = ':'.join(message_data[2:]) # status msg
|
||||||
kind = constants.KIND_GCSTATUS
|
kind = self.constants.KIND_GCSTATUS
|
||||||
elif typ == 'recv':
|
elif typ == 'recv':
|
||||||
message = ':'.join(message_data[0:])
|
message = ':'.join(message_data[0:])
|
||||||
kind = constants.KIND_CHAT_MSG_RECV
|
kind = self.constants.KIND_CHAT_MSG_RECV
|
||||||
elif typ == 'sent':
|
elif typ == 'sent':
|
||||||
message = ':'.join(message_data[0:])
|
message = ':'.join(message_data[0:])
|
||||||
kind = constants.KIND_CHAT_MSG_SENT
|
kind = self.constants.KIND_CHAT_MSG_SENT
|
||||||
else: # status
|
else: # status
|
||||||
kind = constants.KIND_STATUS
|
kind = self.constants.KIND_STATUS
|
||||||
show = message_data[0]
|
show = message_data[0]
|
||||||
message = ':'.join(message_data[1:]) # status msg
|
message = ':'.join(message_data[1:]) # status msg
|
||||||
|
|
||||||
|
@ -174,25 +152,58 @@ def visit(arg, dirname, filenames):
|
||||||
|
|
||||||
# jid is already in the DB, don't create a new row, just get his jid_id
|
# jid is already in the DB, don't create a new row, just get his jid_id
|
||||||
if not JID_ID:
|
if not JID_ID:
|
||||||
if jid in jids_already_in:
|
if jid in self.jids_already_in:
|
||||||
cur.execute('SELECT jid_id FROM jids WHERE jid = "%s"' % jid)
|
self.cur.execute('SELECT jid_id FROM jids WHERE jid = "%s"' % jid)
|
||||||
JID_ID = cur.fetchone()[0]
|
JID_ID = self.cur.fetchone()[0]
|
||||||
else:
|
else:
|
||||||
jids_already_in.append(jid)
|
self.jids_already_in.append(jid)
|
||||||
cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)',
|
self.cur.execute('INSERT INTO jids (jid, type) VALUES (?, ?)',
|
||||||
(jid, jid_type))
|
(jid, jid_type))
|
||||||
con.commit()
|
self.con.commit()
|
||||||
JID_ID = cur.lastrowid
|
JID_ID = self.cur.lastrowid
|
||||||
|
|
||||||
sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message) '\
|
sql = 'INSERT INTO logs (jid_id, contact_name, time, kind, show, message) '\
|
||||||
'VALUES (?, ?, ?, ?, ?, ?)'
|
'VALUES (?, ?, ?, ?, ?, ?)'
|
||||||
|
|
||||||
values = (JID_ID, contact_name, tim, kind, show, message)
|
values = (JID_ID, contact_name, tim, kind, show, message)
|
||||||
cur.execute(sql, values)
|
self.cur.execute(sql, values)
|
||||||
con.commit()
|
self.con.commit()
|
||||||
|
|
||||||
def migrate():
|
def migrate(self, queue = None):
|
||||||
os.path.walk(PATH_TO_LOGS_BASE_DIR, visit, None)
|
self.queue = queue
|
||||||
|
self.con = sqlite.connect(PATH_TO_DB)
|
||||||
|
os.chmod(PATH_TO_DB, 0600) # rw only for us
|
||||||
|
self.cur = self.con.cursor()
|
||||||
|
# create the tables
|
||||||
|
# kind can be
|
||||||
|
# status, gcstatus, gc_msg, (we only recv for those 3),
|
||||||
|
# single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
|
||||||
|
# to meet all our needs
|
||||||
|
# logs.jid_id --> jids.jid_id but Sqlite doesn't do FK etc so it's done in python code
|
||||||
|
self.cur.executescript(
|
||||||
|
'''
|
||||||
|
CREATE TABLE jids(
|
||||||
|
jid_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
jid TEXT UNIQUE,
|
||||||
|
type INTEGER
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE logs(
|
||||||
|
log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
|
jid_id INTEGER,
|
||||||
|
contact_name TEXT,
|
||||||
|
time INTEGER,
|
||||||
|
kind INTEGER,
|
||||||
|
show INTEGER,
|
||||||
|
message TEXT,
|
||||||
|
subject TEXT
|
||||||
|
);
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
|
self.con.commit()
|
||||||
|
|
||||||
|
os.path.walk(PATH_TO_LOGS_BASE_DIR, self.visit, None)
|
||||||
s = '''We do not use plain-text files anymore, because they do not scale.
|
s = '''We do not use plain-text files anymore, because they do not scale.
|
||||||
Those files here are logs for Gajim up until 0.8.2
|
Those files here are logs for Gajim up until 0.8.2
|
||||||
We now use an sqlite database called logs.db found in ~/.gajim
|
We now use an sqlite database called logs.db found in ~/.gajim
|
||||||
|
@ -201,6 +212,9 @@ Thank you''' % PATH_TO_LOGS_BASE_DIR
|
||||||
f = open(os.path.join(PATH_TO_LOGS_BASE_DIR, 'README'), 'w')
|
f = open(os.path.join(PATH_TO_LOGS_BASE_DIR, 'README'), 'w')
|
||||||
f.write(s)
|
f.write(s)
|
||||||
f.close()
|
f.close()
|
||||||
|
if queue:
|
||||||
|
queue.put(s)
|
||||||
|
self.DONE = True
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print 'IMPORTNANT: PLEASE READ http://trac.gajim.org/wiki/MigrateLogToDot9DB'
|
print 'IMPORTNANT: PLEASE READ http://trac.gajim.org/wiki/MigrateLogToDot9DB'
|
||||||
|
@ -210,4 +224,5 @@ if __name__ == '__main__':
|
||||||
print 'Starting Logs Migration'
|
print 'Starting Logs Migration'
|
||||||
print '======================='
|
print '======================='
|
||||||
print 'Please do NOT run Gajim until this script is over'
|
print 'Please do NOT run Gajim until this script is over'
|
||||||
migrate()
|
m = migration()
|
||||||
|
m.migrate()
|
||||||
|
|
|
@ -1277,35 +1277,36 @@ class ProgressDialog:
|
||||||
messages_queue has the message to show
|
messages_queue has the message to show
|
||||||
in the textview'''
|
in the textview'''
|
||||||
self.xml = gtk.glade.XML(GTKGUI_GLADE, 'progress_dialog', APP)
|
self.xml = gtk.glade.XML(GTKGUI_GLADE, 'progress_dialog', APP)
|
||||||
dialog = self.xml.get_widget('progress_dialog')
|
self.dialog = self.xml.get_widget('progress_dialog')
|
||||||
|
self.messages_queue = messages_queue
|
||||||
self.label = self.xml.get_widget('label')
|
self.label = self.xml.get_widget('label')
|
||||||
self.label.set_markup('<big>' + during_text + '</big>')
|
self.label.set_markup('<big>' + during_text + '</big>')
|
||||||
self.progressbar = self.xml.get_widget('progressbar')
|
self.progressbar = self.xml.get_widget('progressbar')
|
||||||
self.textview_buffer = self.xml.get_widget('textview').get_buffer()
|
self.textview = self.xml.get_widget('textview')
|
||||||
|
self.textview_buffer = self.textview.get_buffer()
|
||||||
|
end_iter = self.textview_buffer.get_end_iter()
|
||||||
|
self.textview_buffer.create_mark('end', end_iter, False)
|
||||||
|
|
||||||
dialog.set_title(title_text)
|
self.dialog.set_title(title_text)
|
||||||
dialog.show_all()
|
self.dialog.show_all()
|
||||||
self.xml.signal_autoconnect(self)
|
self.xml.signal_autoconnect(self)
|
||||||
|
|
||||||
self.update_progressbar_timeout_id = gobject.timeout_add(100,
|
self.update_progressbar_timeout_id = gobject.timeout_add(100,
|
||||||
self.update_progressbar)
|
self.update_progressbar)
|
||||||
|
|
||||||
self.read_from_queue_id = gobject.timeout_add(1000,
|
self.read_from_queue_id = gobject.timeout_add(200,
|
||||||
self.read_from_queue_and_update_textview, messages_queue)
|
self.read_from_queue_and_update_textview)
|
||||||
|
|
||||||
def update_progressbar(self):
|
def update_progressbar(self):
|
||||||
self.progressbar.pulse()
|
self.progressbar.pulse()
|
||||||
return True # loop forever
|
return True # loop forever
|
||||||
|
|
||||||
def read_from_queue_and_update_textview(self, messages_queue):
|
def read_from_queue_and_update_textview(self):
|
||||||
try:
|
while not self.messages_queue.empty():
|
||||||
message = messages_queue.get_nowait()
|
message = self.messages_queue.get()
|
||||||
print message
|
|
||||||
except Queue.Empty:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
end_iter = self.textview_buffer.get_end_iter()
|
end_iter = self.textview_buffer.get_end_iter()
|
||||||
self.textview_buffer.insert(end_iter, message)
|
self.textview_buffer.insert(end_iter, message + '\n')
|
||||||
|
self.textview.scroll_to_mark(self.textview_buffer.get_mark('end'), 0, True, 0, 1)
|
||||||
|
|
||||||
return True # loop for ever
|
return True # loop for ever
|
||||||
|
|
||||||
|
@ -1316,6 +1317,7 @@ class ProgressDialog:
|
||||||
'''whatever we were doing is done (either we problems or not),
|
'''whatever we were doing is done (either we problems or not),
|
||||||
make close button sensitive and show the done_text in label'''
|
make close button sensitive and show the done_text in label'''
|
||||||
self.xml.get_widget('close_button').set_sensitive(True)
|
self.xml.get_widget('close_button').set_sensitive(True)
|
||||||
self.label.set_markup('<big>' + done_text + '</big')
|
self.label.set_markup('<big>' + done_text + '</big>')
|
||||||
gobject.source_remove(self.update_progressbar_timeout_id)
|
gobject.source_remove(self.update_progressbar_timeout_id)
|
||||||
gobject.source_remove(self.read_from_queue_id)
|
gobject.source_remove(self.read_from_queue_id)
|
||||||
|
self.read_from_queue_and_update_textview()
|
||||||
|
|
30
src/gajim.py
30
src/gajim.py
|
@ -71,12 +71,6 @@ if pritext:
|
||||||
dlg.destroy()
|
dlg.destroy()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
from common import logger
|
|
||||||
LOG_DB_PATH = logger.LOG_DB_PATH
|
|
||||||
NO_DB = False
|
|
||||||
if not os.path.isfile(LOG_DB_PATH):
|
|
||||||
NO_DB = True
|
|
||||||
|
|
||||||
path = os.getcwd()
|
path = os.getcwd()
|
||||||
if '.svn' in os.listdir(path) or '_svn' in os.listdir(path):
|
if '.svn' in os.listdir(path) or '_svn' in os.listdir(path):
|
||||||
# import gtkexcepthook only for those that run svn
|
# import gtkexcepthook only for those that run svn
|
||||||
|
@ -94,6 +88,7 @@ import sre
|
||||||
import signal
|
import signal
|
||||||
import getopt
|
import getopt
|
||||||
import time
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
import gtkgui_helpers
|
import gtkgui_helpers
|
||||||
import notify
|
import notify
|
||||||
|
@ -1399,6 +1394,14 @@ class Interface:
|
||||||
gobject.timeout_add(200, self.process_connections)
|
gobject.timeout_add(200, self.process_connections)
|
||||||
gobject.timeout_add(500, self.read_sleepy)
|
gobject.timeout_add(500, self.read_sleepy)
|
||||||
|
|
||||||
|
def wait_migration(migration):
|
||||||
|
if not migration.DONE:
|
||||||
|
return True
|
||||||
|
dialog.done(_('Logs have been successfully migrated to the database.'))
|
||||||
|
dialog.dialog.run()
|
||||||
|
dialog.dialog.destroy()
|
||||||
|
gtk.main_quit()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
|
signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
|
||||||
|
|
||||||
|
@ -1460,9 +1463,18 @@ if __name__ == '__main__':
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Migrate old logs if user wants that
|
# Migrate old logs if user wants that
|
||||||
if NO_DB:
|
from common import logger
|
||||||
pass # launch migration script
|
LOG_DB_PATH = logger.LOG_DB_PATH
|
||||||
del NO_DB
|
if not os.path.isfile(LOG_DB_PATH):
|
||||||
|
import Queue
|
||||||
|
q = Queue.Queue(100)
|
||||||
|
from common import migrate_logs_to_dot9_db
|
||||||
|
m = migrate_logs_to_dot9_db.migration()
|
||||||
|
dialog = dialogs.ProgressDialog(_('Migrating logs...'), _('Please wait while logs are being migrated...'), q)
|
||||||
|
t = threading.Thread(target = m.migrate, args = (q,))
|
||||||
|
t.start()
|
||||||
|
gobject.timeout_add(500, wait_migration, m)
|
||||||
|
gtk.main()
|
||||||
check_paths.check_and_possibly_create_paths()
|
check_paths.check_and_possibly_create_paths()
|
||||||
|
|
||||||
Interface()
|
Interface()
|
||||||
|
|
Loading…
Add table
Reference in a new issue