Extract dialogs into their own module
This commit is contained in:
parent
74ef6650a0
commit
8b1b7cbe7e
|
@ -0,0 +1,194 @@
|
|||
# Diffuse: a graphical tool for merging and comparing text files.
|
||||
#
|
||||
# Copyright (C) 2019 Derrick Moser <derrick_moser@yahoo.com>
|
||||
# Copyright (C) 2021 Romain Failliot <romain.failliot@foolstep.com>
|
||||
#
|
||||
# This program 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; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import os
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
import gi
|
||||
gi.require_version('GObject', '2.0')
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import GObject, Gtk
|
||||
# pylint: enable=wrong-import-position
|
||||
|
||||
from diffuse import constants
|
||||
from diffuse import utils
|
||||
|
||||
# the about dialog
|
||||
class AboutDialog(Gtk.AboutDialog):
|
||||
def __init__(self):
|
||||
Gtk.AboutDialog.__init__(self)
|
||||
self.set_logo_icon_name('io.github.mightycreak.Diffuse')
|
||||
self.set_program_name(constants.APP_NAME)
|
||||
self.set_version(constants.VERSION)
|
||||
self.set_comments(_('Diffuse is a graphical tool for merging and comparing text files.'))
|
||||
self.set_copyright(constants.COPYRIGHT)
|
||||
self.set_website(constants.WEBSITE)
|
||||
self.set_authors([ 'Derrick Moser <derrick_moser@yahoo.com>',
|
||||
'Romain Failliot <romain.failliot@foolstep.com>' ])
|
||||
self.set_translator_credits(_('translator-credits'))
|
||||
license_text = [
|
||||
constants.APP_NAME + ' ' + constants.VERSION + '\n\n',
|
||||
constants.COPYRIGHT + '\n\n',
|
||||
_('''This program 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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.''') ]
|
||||
self.set_license(''.join(license_text))
|
||||
|
||||
# custom dialogue for picking files with widgets for specifying the encoding
|
||||
# and revision
|
||||
class FileChooserDialog(Gtk.FileChooserDialog):
|
||||
# record last chosen folder so the file chooser can start at a more useful
|
||||
# location for empty panes
|
||||
last_chosen_folder = os.path.realpath(os.curdir)
|
||||
|
||||
def __current_folder_changed_cb(self, widget):
|
||||
FileChooserDialog.last_chosen_folder = widget.get_current_folder()
|
||||
|
||||
def __init__(self, title, parent, prefs, action, accept, rev=False):
|
||||
Gtk.FileChooserDialog.__init__(self, title=title, parent=parent, action=action)
|
||||
self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
|
||||
self.add_button(accept, Gtk.ResponseType.OK)
|
||||
self.prefs = prefs
|
||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||
hbox.set_border_width(5)
|
||||
label = Gtk.Label.new(_('Encoding: '))
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label.show()
|
||||
self.encoding = entry = utils.EncodingMenu(
|
||||
prefs,
|
||||
action in [ Gtk.FileChooserAction.OPEN, Gtk.FileChooserAction.SELECT_FOLDER ])
|
||||
hbox.pack_start(entry, False, False, 5)
|
||||
entry.show()
|
||||
if rev:
|
||||
self.revision = entry = Gtk.Entry.new()
|
||||
hbox.pack_end(entry, False, False, 0)
|
||||
entry.show()
|
||||
label = Gtk.Label.new(_('Revision: '))
|
||||
hbox.pack_end(label, False, False, 0)
|
||||
label.show()
|
||||
|
||||
self.vbox.pack_start(hbox, False, False, 0) # pylint: disable=no-member
|
||||
hbox.show()
|
||||
self.set_current_folder(self.last_chosen_folder)
|
||||
self.connect('current-folder-changed', self.__current_folder_changed_cb)
|
||||
|
||||
def set_encoding(self, encoding):
|
||||
self.encoding.set_text(encoding)
|
||||
|
||||
def get_encoding(self):
|
||||
return self.encoding.get_text()
|
||||
|
||||
def get_revision(self):
|
||||
return self.revision.get_text()
|
||||
|
||||
def get_filename(self):
|
||||
# convert from UTF-8 string to unicode
|
||||
return Gtk.FileChooserDialog.get_filename(self) # pylint: disable=no-member
|
||||
|
||||
# dialogue used to search for text
|
||||
class NumericDialog(Gtk.Dialog):
|
||||
def __init__(self, parent, title, text, val, lower, upper, step=1, page=0):
|
||||
Gtk.Dialog.__init__(self, title=title, parent=parent, destroy_with_parent=True)
|
||||
self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
|
||||
self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
|
||||
|
||||
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
|
||||
vbox.set_border_width(10)
|
||||
|
||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||
label = Gtk.Label.new(text)
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label.show()
|
||||
adj = Gtk.Adjustment.new(val, lower, upper, step, page, 0)
|
||||
self.button = button = Gtk.SpinButton.new(adj, 1.0, 0)
|
||||
button.connect('activate', self.button_cb)
|
||||
hbox.pack_start(button, True, True, 0)
|
||||
button.show()
|
||||
|
||||
vbox.pack_start(hbox, True, True, 0)
|
||||
hbox.show()
|
||||
|
||||
self.vbox.pack_start(vbox, False, False, 0) # pylint: disable=no-member
|
||||
vbox.show()
|
||||
|
||||
def button_cb(self, widget):
|
||||
self.response(Gtk.ResponseType.ACCEPT)
|
||||
|
||||
# dialogue used to search for text
|
||||
class SearchDialog(Gtk.Dialog):
|
||||
def __init__(self, parent, pattern=None, history=None):
|
||||
Gtk.Dialog.__init__(self, title=_('Find...'), parent=parent, destroy_with_parent=True)
|
||||
self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
|
||||
self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
|
||||
|
||||
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
|
||||
vbox.set_border_width(10)
|
||||
|
||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||
label = Gtk.Label.new(_('Search For: '))
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label.show()
|
||||
combo = Gtk.ComboBoxText.new_with_entry()
|
||||
self.entry = combo.get_child()
|
||||
self.entry.connect('activate', self.entry_cb)
|
||||
|
||||
if pattern is not None:
|
||||
self.entry.set_text(pattern)
|
||||
|
||||
if history is not None:
|
||||
completion = Gtk.EntryCompletion.new()
|
||||
liststore = Gtk.ListStore(GObject.TYPE_STRING)
|
||||
completion.set_model(liststore)
|
||||
completion.set_text_column(0)
|
||||
for h in history:
|
||||
liststore.append([h])
|
||||
combo.append_text(h)
|
||||
self.entry.set_completion(completion)
|
||||
|
||||
hbox.pack_start(combo, True, True, 0)
|
||||
combo.show()
|
||||
vbox.pack_start(hbox, False, False, 0)
|
||||
hbox.show()
|
||||
|
||||
button = Gtk.CheckButton.new_with_mnemonic(_('Match Case'))
|
||||
self.match_case_button = button
|
||||
vbox.pack_start(button, False, False, 0)
|
||||
button.show()
|
||||
|
||||
button = Gtk.CheckButton.new_with_mnemonic(_('Search Backwards'))
|
||||
self.backwards_button = button
|
||||
vbox.pack_start(button, False, False, 0)
|
||||
button.show()
|
||||
|
||||
self.vbox.pack_start(vbox, False, False, 0) # pylint: disable=no-member
|
||||
vbox.show()
|
||||
|
||||
# callback used when the Enter key is pressed
|
||||
def entry_cb(self, widget):
|
||||
self.response(Gtk.ResponseType.ACCEPT)
|
197
src/main.py
197
src/main.py
|
@ -22,8 +22,6 @@ import sys
|
|||
import codecs
|
||||
import difflib
|
||||
import encodings
|
||||
import glob
|
||||
import re
|
||||
import shlex
|
||||
import stat
|
||||
import unicodedata
|
||||
|
@ -42,8 +40,9 @@ from gi.repository import GObject, Gtk, Gdk, GdkPixbuf, Pango, PangoCairo
|
|||
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from diffuse import utils
|
||||
from diffuse import constants
|
||||
from diffuse import utils
|
||||
from diffuse.dialogs import AboutDialog, FileChooserDialog, NumericDialog, SearchDialog
|
||||
from diffuse.preferences import Preferences
|
||||
from diffuse.resources import Resources
|
||||
from diffuse.vcs.vcs_registry import VcsRegistry
|
||||
|
@ -146,7 +145,7 @@ def has_unix_line_ending(s):
|
|||
return s.endswith('\n') and not s.endswith('\r\n')
|
||||
|
||||
# returns the format mask for a list of strings
|
||||
def getFormat(ss):
|
||||
def get_format(ss):
|
||||
flags = 0
|
||||
for s in ss:
|
||||
if s is not None:
|
||||
|
@ -161,7 +160,7 @@ def getFormat(ss):
|
|||
# convenience method to change the line ending of a string
|
||||
def convert_to_format(s, format):
|
||||
if s is not None and format != 0:
|
||||
old_format = getFormat([ s ])
|
||||
old_format = get_format([ s ])
|
||||
if old_format != 0 and (old_format & format) == 0:
|
||||
s = utils.strip_eol(s)
|
||||
# prefer the host line ending style
|
||||
|
@ -436,7 +435,7 @@ def getCharacterClass(c):
|
|||
return OTHER_CLASS
|
||||
|
||||
# longest common subsequence of unique elements common to 'a' and 'b'
|
||||
def __patience_subsequence(a, b):
|
||||
def _patience_subsequence(a, b):
|
||||
# value unique lines by their order in each list
|
||||
value_a, value_b = {}, {}
|
||||
# find unique values in 'a'
|
||||
|
@ -491,7 +490,7 @@ def __patience_subsequence(a, b):
|
|||
return result
|
||||
|
||||
# difflib-style approximation of the longest common subsequence
|
||||
def __lcs_approx(a, b):
|
||||
def _lcs_approx(a, b):
|
||||
count1, lookup = {}, {}
|
||||
# count occurrences of each element in 'a'
|
||||
for s in a:
|
||||
|
@ -562,8 +561,8 @@ def __lcs_approx(a, b):
|
|||
aidx, bidx, nidx = ai, bi, n
|
||||
return aidx, bidx, nidx
|
||||
|
||||
# patinence diff with difflib-style fallback
|
||||
def patience_diff(a, b):
|
||||
# patience diff with difflib-style fallback
|
||||
def _patience_diff(a, b):
|
||||
matches, len_a, len_b = [], len(a), len(b)
|
||||
if len_a and len_b:
|
||||
blocks = [ (0, len_a, 0, len_b, 0) ]
|
||||
|
@ -571,7 +570,7 @@ def patience_diff(a, b):
|
|||
start_a, end_a, start_b, end_b, match_idx = blocks.pop()
|
||||
aa, bb = a[start_a:end_a], b[start_b:end_b]
|
||||
# try patience
|
||||
pivots = __patience_subsequence(aa, bb)
|
||||
pivots = _patience_subsequence(aa, bb)
|
||||
if pivots:
|
||||
offset_a, offset_b = start_a, start_b
|
||||
for pivot_a, pivot_b in pivots:
|
||||
|
@ -599,7 +598,7 @@ def patience_diff(a, b):
|
|||
blocks.append((start_a, end_a, start_b, end_b, match_idx))
|
||||
else:
|
||||
# fallback if patience fails
|
||||
pivots = __lcs_approx(aa, bb)
|
||||
pivots = _lcs_approx(aa, bb)
|
||||
if pivots:
|
||||
idx_a, idx_b, n = pivots
|
||||
idx_a += start_a
|
||||
|
@ -1600,7 +1599,7 @@ class FileDiffViewer(Gtk.Grid):
|
|||
# align s1 and s2 by inserting spacer lines
|
||||
# this will be used to determine which lines from the inner lists of
|
||||
# lines should be neighbours
|
||||
for block in patience_diff(t1, t2):
|
||||
for block in _patience_diff(t1, t2):
|
||||
delta = (n1 + block[0]) - (n2 + block[1])
|
||||
if delta < 0:
|
||||
# insert spacer lines in s1
|
||||
|
@ -1679,7 +1678,7 @@ class FileDiffViewer(Gtk.Grid):
|
|||
def replaceContents(self, f, ss):
|
||||
self.alignmentChange(False)
|
||||
# determine the format for the text
|
||||
self.setFormat(f, getFormat(ss))
|
||||
self.setFormat(f, get_format(ss))
|
||||
|
||||
# create an initial set of blocks for the lines
|
||||
blocks = []
|
||||
|
@ -1786,7 +1785,7 @@ class FileDiffViewer(Gtk.Grid):
|
|||
ss.append('')
|
||||
# change the format to that of the target pane
|
||||
if pane.format == 0:
|
||||
self.setFormat(f, getFormat(ss))
|
||||
self.setFormat(f, get_format(ss))
|
||||
ss = [ convert_to_format(s, pane.format) for s in ss ]
|
||||
# prepend original text that was before the selection
|
||||
if col0 > 0:
|
||||
|
@ -3968,7 +3967,7 @@ class FileDiffViewer(Gtk.Grid):
|
|||
if pane.format == 0:
|
||||
# copy the format of the source pane if the format for the
|
||||
# destination pane as not yet been determined
|
||||
self.setFormat(f_dst, getFormat(ss))
|
||||
self.setFormat(f_dst, get_format(ss))
|
||||
for i, s in enumerate(ss):
|
||||
self.updateText(f_dst, start + i, convert_to_format(s, pane.format))
|
||||
n = len(ss)
|
||||
|
@ -4107,59 +4106,6 @@ GObject.signal_new('cursor-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAS
|
|||
GObject.signal_new('syntax-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (str, ))
|
||||
GObject.signal_new('format-changed', FileDiffViewer, GObject.SignalFlags.RUN_LAST, GObject.TYPE_NONE, (int, int))
|
||||
|
||||
# dialogue used to search for text
|
||||
class SearchDialog(Gtk.Dialog):
|
||||
def __init__(self, parent, pattern=None, history=None):
|
||||
Gtk.Dialog.__init__(self, title=_('Find...'), parent=parent, destroy_with_parent=True)
|
||||
self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
|
||||
self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
|
||||
|
||||
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
|
||||
vbox.set_border_width(10)
|
||||
|
||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||
label = Gtk.Label.new(_('Search For: '))
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label.show()
|
||||
combo = Gtk.ComboBoxText.new_with_entry()
|
||||
self.entry = combo.get_child()
|
||||
self.entry.connect('activate', self.entry_cb)
|
||||
|
||||
if pattern is not None:
|
||||
self.entry.set_text(pattern)
|
||||
|
||||
if history is not None:
|
||||
completion = Gtk.EntryCompletion.new()
|
||||
liststore = Gtk.ListStore(GObject.TYPE_STRING)
|
||||
completion.set_model(liststore)
|
||||
completion.set_text_column(0)
|
||||
for h in history:
|
||||
liststore.append([h])
|
||||
combo.append_text(h)
|
||||
self.entry.set_completion(completion)
|
||||
|
||||
hbox.pack_start(combo, True, True, 0)
|
||||
combo.show()
|
||||
vbox.pack_start(hbox, False, False, 0)
|
||||
hbox.show()
|
||||
|
||||
button = Gtk.CheckButton.new_with_mnemonic(_('Match Case'))
|
||||
self.match_case_button = button
|
||||
vbox.pack_start(button, False, False, 0)
|
||||
button.show()
|
||||
|
||||
button = Gtk.CheckButton.new_with_mnemonic(_('Search Backwards'))
|
||||
self.backwards_button = button
|
||||
vbox.pack_start(button, False, False, 0)
|
||||
button.show()
|
||||
|
||||
self.vbox.pack_start(vbox, False, False, 0) # pylint: disable=no-member
|
||||
vbox.show()
|
||||
|
||||
# callback used when the Enter key is pressed
|
||||
def entry_cb(self, widget):
|
||||
self.response(Gtk.ResponseType.ACCEPT)
|
||||
|
||||
# convenience method to request confirmation when closing the last tab
|
||||
def confirmTabClose(parent):
|
||||
dialog = utils.MessageDialog(parent, Gtk.MessageType.WARNING, _('Closing this tab will quit %s.') % (constants.APP_NAME, ))
|
||||
|
@ -4167,121 +4113,6 @@ def confirmTabClose(parent):
|
|||
dialog.destroy()
|
||||
return end
|
||||
|
||||
# custom dialogue for picking files with widgets for specifying the encoding
|
||||
# and revision
|
||||
class FileChooserDialog(Gtk.FileChooserDialog):
|
||||
# record last chosen folder so the file chooser can start at a more useful
|
||||
# location for empty panes
|
||||
last_chosen_folder = os.path.realpath(os.curdir)
|
||||
|
||||
def __current_folder_changed_cb(self, widget):
|
||||
FileChooserDialog.last_chosen_folder = widget.get_current_folder()
|
||||
|
||||
def __init__(self, title, parent, prefs, action, accept, rev=False):
|
||||
Gtk.FileChooserDialog.__init__(self, title=title, parent=parent, action=action)
|
||||
self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
|
||||
self.add_button(accept, Gtk.ResponseType.OK)
|
||||
self.prefs = prefs
|
||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||
hbox.set_border_width(5)
|
||||
label = Gtk.Label.new(_('Encoding: '))
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label.show()
|
||||
self.encoding = entry = utils.EncodingMenu(prefs, action in [ Gtk.FileChooserAction.OPEN, Gtk.FileChooserAction.SELECT_FOLDER ])
|
||||
hbox.pack_start(entry, False, False, 5)
|
||||
entry.show()
|
||||
if rev:
|
||||
self.revision = entry = Gtk.Entry.new()
|
||||
hbox.pack_end(entry, False, False, 0)
|
||||
entry.show()
|
||||
label = Gtk.Label.new(_('Revision: '))
|
||||
hbox.pack_end(label, False, False, 0)
|
||||
label.show()
|
||||
|
||||
self.vbox.pack_start(hbox, False, False, 0) # pylint: disable=no-member
|
||||
hbox.show()
|
||||
self.set_current_folder(self.last_chosen_folder)
|
||||
self.connect('current-folder-changed', self.__current_folder_changed_cb)
|
||||
|
||||
def set_encoding(self, encoding):
|
||||
self.encoding.set_text(encoding)
|
||||
|
||||
def get_encoding(self):
|
||||
return self.encoding.get_text()
|
||||
|
||||
def get_revision(self):
|
||||
return self.revision.get_text()
|
||||
|
||||
def get_filename(self):
|
||||
# convert from UTF-8 string to unicode
|
||||
return Gtk.FileChooserDialog.get_filename(self)
|
||||
|
||||
# dialogue used to search for text
|
||||
class NumericDialog(Gtk.Dialog):
|
||||
def __init__(self, parent, title, text, val, lower, upper, step=1, page=0):
|
||||
Gtk.Dialog.__init__(self, title=title, parent=parent, destroy_with_parent=True)
|
||||
self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.REJECT)
|
||||
self.add_button(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
|
||||
|
||||
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
|
||||
vbox.set_border_width(10)
|
||||
|
||||
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
|
||||
label = Gtk.Label.new(text)
|
||||
hbox.pack_start(label, False, False, 0)
|
||||
label.show()
|
||||
adj = Gtk.Adjustment.new(val, lower, upper, step, page, 0)
|
||||
self.button = button = Gtk.SpinButton.new(adj, 1.0, 0)
|
||||
button.connect('activate', self.button_cb)
|
||||
hbox.pack_start(button, True, True, 0)
|
||||
button.show()
|
||||
|
||||
vbox.pack_start(hbox, True, True, 0)
|
||||
hbox.show()
|
||||
|
||||
self.vbox.pack_start(vbox, False, False, 0) # pylint: disable=no-member
|
||||
vbox.show()
|
||||
|
||||
def button_cb(self, widget):
|
||||
self.response(Gtk.ResponseType.ACCEPT)
|
||||
|
||||
# establish callback for the about dialog's link to Diffuse's web site
|
||||
def url_hook(dialog, link, userdata):
|
||||
webbrowser.open(link)
|
||||
|
||||
|
||||
|
||||
# the about dialog
|
||||
class AboutDialog(Gtk.AboutDialog):
|
||||
def __init__(self):
|
||||
Gtk.AboutDialog.__init__(self)
|
||||
self.set_logo_icon_name('io.github.mightycreak.Diffuse')
|
||||
self.set_program_name(constants.APP_NAME)
|
||||
self.set_version(constants.VERSION)
|
||||
self.set_comments(_('Diffuse is a graphical tool for merging and comparing text files.'))
|
||||
self.set_copyright(constants.COPYRIGHT)
|
||||
self.set_website(constants.WEBSITE)
|
||||
self.set_authors([ 'Derrick Moser <derrick_moser@yahoo.com>',
|
||||
'Romain Failliot <romain.failliot@foolstep.com>' ])
|
||||
self.set_translator_credits(_('translator-credits'))
|
||||
license_text = [
|
||||
constants.APP_NAME + ' ' + constants.VERSION + '\n\n',
|
||||
constants.COPYRIGHT + '\n\n',
|
||||
_('''This program 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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.''') ]
|
||||
self.set_license(''.join(license_text))
|
||||
|
||||
# widget classed to create notebook tabs with labels and a close button
|
||||
# use notebooktab.button.connect() to be notified when the button is pressed
|
||||
# make this a Gtk.EventBox so signals can be connected for MMB and RMB button
|
||||
|
|
|
@ -32,6 +32,7 @@ configure_file(
|
|||
|
||||
diffuse_sources = [
|
||||
'__init__.py',
|
||||
'dialogs.py',
|
||||
'main.py',
|
||||
'preferences.py',
|
||||
'resources.py',
|
||||
|
|
Loading…
Reference in New Issue