Blame plugins/colorschemer/schemer/schemer.py

Packit 6978fb
#!/usr/bin/python
Packit 6978fb
#
Packit 6978fb
# Gedit Scheme Editor
Packit 6978fb
# https://github.com/jonocodes/GeditSchemer
Packit 6978fb
#
Packit 6978fb
# Copyright (C) Jono Finger 2013 <jono@foodnotblogs.com>
Packit 6978fb
# 
Packit 6978fb
# The program is free software: you can redistribute it and/or modify it
Packit 6978fb
# under the terms of the GNU General Public License as published by the
Packit 6978fb
# Free Software Foundation, either version 2 of the License, or
Packit 6978fb
# (at your option) any later version.
Packit 6978fb
# 
Packit 6978fb
# The program is distributed in the hope that it will be useful, but
Packit 6978fb
# WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6978fb
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit 6978fb
# See the GNU General Public License for more details.
Packit 6978fb
# 
Packit 6978fb
# You should have received a copy of the GNU General Public License along
Packit 6978fb
# with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 6978fb
Packit 6978fb
import os
Packit 6978fb
import sys
Packit 6978fb
import collections
Packit 6978fb
import tempfile
Packit 6978fb
from xml.etree import ElementTree as ET
Packit 6978fb
Packit 6978fb
from gi.repository import Gtk, GdkPixbuf, Gdk, GtkSource, Gio, GLib
Packit 6978fb
Packit 6978fb
from .languages import samples
Packit 6978fb
Packit 6978fb
Packit 6978fb
# Holds style properties for a GtkSourceStyle element
Packit 6978fb
class Props:
Packit 6978fb
Packit 6978fb
  def __init__(self):
Packit 6978fb
  
Packit 6978fb
    self.background = None  # str
Packit 6978fb
    self.foreground = None  # str
Packit 6978fb
    self.italic = False
Packit 6978fb
    self.bold = False
Packit 6978fb
    self.strikethrough = False
Packit 6978fb
    self.underline = False
Packit 6978fb
    
Packit 6978fb
  def is_clear(self):
Packit 6978fb
    """ Return true if all the attributes are at the defaults/unset """
Packit 6978fb
    
Packit 6978fb
    return (self.foreground == None and 
Packit 6978fb
        self.background == None and 
Packit 6978fb
        self.bold == False and 
Packit 6978fb
        self.italic == False and 
Packit 6978fb
        self.underline == False and 
Packit 6978fb
        self.strikethrough == False)
Packit 6978fb
    
Packit 6978fb
  def from_gtk_source_style(self, gtkStyle):
Packit 6978fb
  
Packit 6978fb
    self.background = gtkStyle.props.background
Packit 6978fb
    self.foreground = gtkStyle.props.foreground
Packit 6978fb
    self.italic = gtkStyle.props.italic
Packit 6978fb
    self.bold = gtkStyle.props.bold
Packit 6978fb
    self.underline = gtkStyle.props.underline
Packit 6978fb
    self.strikethrough = gtkStyle.props.strikethrough
Packit 6978fb
    
Packit 6978fb
    # here we make sure every color starts with a hash
Packit 6978fb
    # maybe this is a workaround for a bug that I should file
Packit 6978fb
    # or maybe this is a false assumption
Packit 6978fb
Packit 6978fb
    # if self.foreground and self.foreground[0] != '#':
Packit 6978fb
    #   self.foreground = '#' + self.foreground
Packit 6978fb
      
Packit 6978fb
    # if self.background and self.background[0] != '#':
Packit 6978fb
    #   self.background = '#' + self.background
Packit 6978fb
    
Packit 6978fb
Packit 6978fb
class GUI:
Packit 6978fb
  
Packit 6978fb
  def __init__(self, geditApp, uiDir):
Packit 6978fb
Packit 6978fb
    # constants
Packit 6978fb
Packit 6978fb
    self.colorBlack = Gdk.color_parse('#000000');
Packit 6978fb
    
Packit 6978fb
    # we set this explicitly since the API does not give us a method for it
Packit 6978fb
    self.guiStyleIds = ['bracket-match', 'bracket-mismatch',
Packit 6978fb
      'current-line', 'cursor', 'line-numbers', 'secondary-cursor',
Packit 6978fb
      'selection', 'selection-unfocused', 'text']
Packit 6978fb
Packit 6978fb
    # set up GUI widgets and signals
Packit 6978fb
    
Packit 6978fb
    GtkSource.View() # hack to get GtkSourceView widget to run from glade file
Packit 6978fb
Packit 6978fb
    self.builder = Gtk.Builder()
Packit 6978fb
Packit 6978fb
    uiFile = os.path.join(uiDir, 'schemer.ui')
Packit 6978fb
Packit 6978fb
    if (os.path.isfile(uiFile)):
Packit 6978fb
      self.builder.add_from_file(uiFile)
Packit 6978fb
    else:
Packit 6978fb
      print('unable to find UI file')
Packit 6978fb
      sys.exit(1)
Packit 6978fb
    
Packit 6978fb
    self.builder.connect_signals(self)
Packit 6978fb
    
Packit 6978fb
    self.window = self.builder.get_object('window')
Packit 6978fb
    self.aboutDialog = self.builder.get_object('aboutdialog')
Packit 6978fb
    
Packit 6978fb
    self.sourceBuffer = GtkSource.Buffer(max_undo_levels=0)
Packit 6978fb
    self.sourceView = self.builder.get_object('gtksourceviewSample')
Packit 6978fb
    self.sourceView.set_buffer(self.sourceBuffer)
Packit 6978fb
    
Packit 6978fb
    self.liststoreStyles = self.builder.get_object('liststoreStyles')
Packit 6978fb
    self.liststoreLanguages = self.builder.get_object('liststoreLanguages')
Packit 6978fb
    self.comboboxLanguages = self.builder.get_object('comboboxLanguages')
Packit 6978fb
    self.treeviewStyles = self.builder.get_object('treeviewStyles')
Packit 6978fb
    
Packit 6978fb
    self.colorbuttonForeground = self.builder.get_object('colorbuttonForeground')
Packit 6978fb
    self.colorbuttonBackground = self.builder.get_object('colorbuttonBackground')
Packit 6978fb
    self.togglebuttonItalic = self.builder.get_object('togglebuttonItalic')
Packit 6978fb
    self.togglebuttonBold = self.builder.get_object('togglebuttonBold')
Packit 6978fb
    self.togglebuttonUnderline = self.builder.get_object('togglebuttonUnderline')
Packit 6978fb
    self.togglebuttonStrikethrough = self.builder.get_object('togglebuttonStrikethrough')
Packit 6978fb
    self.checkbuttonForeground = self.builder.get_object('checkbuttonForeground')
Packit 6978fb
    self.checkbuttonBackground = self.builder.get_object('checkbuttonBackground')
Packit 6978fb
    self.resetButton = self.builder.get_object('resetButton')
Packit 6978fb
    
Packit 6978fb
    self.entryName = self.builder.get_object('entryName')
Packit 6978fb
    self.entryAuthor = self.builder.get_object('entryAuthor')
Packit 6978fb
    self.entryDescription = self.builder.get_object('entryDescription')
Packit 6978fb
    self.entryId = self.builder.get_object('entryId')
Packit 6978fb
    self.labelSample = self.builder.get_object('labelSample')
Packit 6978fb
    
Packit 6978fb
    self.colorbuttonBackground.connect('color-set', self.on_style_changed)
Packit 6978fb
    self.colorbuttonForeground.connect('color-set', self.on_style_changed)
Packit 6978fb
Packit 6978fb
    self.builder.get_object('buttonCancel').connect('clicked', self.on_cancel_clicked)
Packit 6978fb
    self.builder.get_object('buttonSave').connect('clicked', self.on_save_clicked)
Packit 6978fb
    
Packit 6978fb
    self.togglebuttonItalicHandler = self.togglebuttonItalic.connect(
Packit 6978fb
      'toggled', self.on_style_changed)
Packit 6978fb
    self.togglebuttonBoldHandler = self.togglebuttonBold.connect(
Packit 6978fb
      'toggled', self.on_style_changed)
Packit 6978fb
    self.togglebuttonUnderlineHandler = self.togglebuttonUnderline.connect(
Packit 6978fb
      'toggled', self.on_style_changed)
Packit 6978fb
    self.togglebuttonStrikethroughHandler = self.togglebuttonStrikethrough.connect(
Packit 6978fb
      'toggled', self.on_style_changed)
Packit 6978fb
    
Packit 6978fb
    self.checkbuttonBackgroundHandler =  self.checkbuttonBackground.connect(
Packit 6978fb
      'toggled', self.on_background_toggled)
Packit 6978fb
    self.checkbuttonForegroundHandler = self.checkbuttonForeground.connect(
Packit 6978fb
      'toggled', self.on_foreground_toggled)
Packit 6978fb
    
Packit 6978fb
    self.resetButton.connect('clicked', self.on_reset_clicked)
Packit 6978fb
    
Packit 6978fb
    self.schemeManager = GtkSource.StyleSchemeManager().get_default() # requires gedit 3.3.3 or newer
Packit 6978fb
    self.languageManager = GtkSource.LanguageManager()
Packit 6978fb
Packit 6978fb
    self.dictAllStyles = collections.OrderedDict()
Packit 6978fb
    
Packit 6978fb
    languages = self.languageManager.get_language_ids()
Packit 6978fb
Packit 6978fb
    self.geditApp = geditApp
Packit 6978fb
    self.geditView = geditApp.get_default().get_active_window().get_active_view()
Packit 6978fb
Packit 6978fb
    self.defaultLanguageId = 'c'
Packit 6978fb
    self.defaultLanguageName = 'C'
Packit 6978fb
    self.defaultLanguage = self.languageManager.get_language(self.defaultLanguageId)
Packit 6978fb
Packit 6978fb
    self.selectedLanguageId = self.defaultLanguageId
Packit 6978fb
    self.selectedLanguageName = self.defaultLanguageName
Packit 6978fb
    self.selectedLanguage = self.defaultLanguage
Packit 6978fb
Packit 6978fb
    self.bufferLanguageId = self.defaultLanguageId
Packit 6978fb
    self.bufferLanguageName = self.defaultLanguageName
Packit 6978fb
    self.bufferLanguage = self.defaultLanguage
Packit 6978fb
Packit 6978fb
    # guess the language from the current buffer
Packit 6978fb
    if self.geditView:
Packit 6978fb
      bufferLanguage = self.geditView.get_buffer().get_language()
Packit 6978fb
Packit 6978fb
      if bufferLanguage and bufferLanguage.get_id() in languages:
Packit 6978fb
        self.bufferLanguageId = bufferLanguage.get_id()
Packit 6978fb
        self.bufferLanguageName = bufferLanguage.get_name()
Packit 6978fb
        self.bufferLanguage = bufferLanguage
Packit 6978fb
Packit 6978fb
    # watch temp directory to help the sample viewer
Packit 6978fb
    self.schemeManagerOrigSearchPath = self.schemeManager.get_search_path()
Packit 6978fb
    self.schemeManager.append_search_path(tempfile.gettempdir())
Packit 6978fb
Packit 6978fb
    self.origSchemeFile = None
Packit 6978fb
Packit 6978fb
    if self.geditView: # if there is a view open, get the scheme from the buffer
Packit 6978fb
      self.load_scheme(self.geditView.get_buffer().get_style_scheme().get_filename())
Packit 6978fb
    else: # is there is no view, check gsettings
Packit 6978fb
      self.load_scheme(Gio.Settings('org.gnome.gedit.preferences.editor').get_string('scheme'))
Packit 6978fb
    
Packit 6978fb
    for langStyleId in self.guiStyleIds:
Packit 6978fb
      self.liststoreStyles.append([langStyleId])
Packit 6978fb
    
Packit 6978fb
    self.langMapNameToId = {}
Packit 6978fb
    
Packit 6978fb
    # make a special case for Defaults which is moved to the top and includes GUI styles
Packit 6978fb
    self.liststoreLanguages.append(['  Default styles'])
Packit 6978fb
    self.langMapNameToId['  Default styles'] = 'def'
Packit 6978fb
    
Packit 6978fb
    langs = []
Packit 6978fb
    
Packit 6978fb
    for thisLanguage in languages:
Packit 6978fb
      langName = self.languageManager.get_language(thisLanguage).get_name()
Packit 6978fb
      self.langMapNameToId[langName] = thisLanguage
Packit 6978fb
      
Packit 6978fb
      if langName != 'Defaults':
Packit 6978fb
        langs.append(langName)
Packit 6978fb
        
Packit 6978fb
    langs.sort(key=lambda y: y.lower())
Packit 6978fb
    
Packit 6978fb
    for langName in langs:
Packit 6978fb
      self.liststoreLanguages.append([langName]);
Packit 6978fb
        
Packit 6978fb
    renderer_text = Gtk.CellRendererText()
Packit 6978fb
    self.comboboxLanguages.pack_start(renderer_text, True)
Packit 6978fb
    self.comboboxLanguages.connect('changed', self.on_language_selected)
Packit 6978fb
    self.comboboxLanguages.add_attribute(renderer_text, 'text', 0)
Packit 6978fb
Packit 6978fb
    self.treeviewStylesSelection = self.treeviewStyles.get_selection()
Packit 6978fb
    self.treeviewStylesSelection.connect('changed', self.on_style_selected)
Packit 6978fb
    
Packit 6978fb
    # select the first language
Packit 6978fb
    self.comboboxLanguages.set_active(0)
Packit 6978fb
    
Packit 6978fb
    # select the first style
Packit 6978fb
    treeIter = self.treeviewStyles.get_model().get_iter_first()
Packit 6978fb
    self.treeviewStylesSelection.select_iter(treeIter)
Packit 6978fb
    model = self.treeviewStyles.get_model()
Packit 6978fb
    self.selectedStyleId = model[treeIter][0]
Packit 6978fb
  
Packit 6978fb
  def destroy(self, window):
Packit 6978fb
    self.window.destroy()
Packit 6978fb
    
Packit 6978fb
  def on_cancel_clicked(self, param):
Packit 6978fb
    self.schemeManager.set_search_path(self.schemeManagerOrigSearchPath)
Packit 6978fb
    self.window.destroy()
Packit 6978fb
Packit 6978fb
  def on_save_clicked(self, param):
Packit 6978fb
Packit 6978fb
    inFile = self.origSchemeFile
Packit 6978fb
Packit 6978fb
    tempDirectory = tempfile.gettempdir()
Packit 6978fb
Packit 6978fb
    outFile = None
Packit 6978fb
Packit 6978fb
    # check to see if they choose a new ID or Name. Create a new file if they did.
Packit 6978fb
    
Packit 6978fb
    nameOrIdChange = False
Packit 6978fb
    
Packit 6978fb
    if (self.currentScheme.get_name() != self.entryName.get_text() or
Packit 6978fb
        self.currentScheme.get_id()   != self.entryId.get_text()):
Packit 6978fb
      # make sure the new name/id does not conflict with one that exists already
Packit 6978fb
      
Packit 6978fb
      schemeIds = self.schemeManager.get_scheme_ids()
Packit 6978fb
Packit 6978fb
      for thisSchemeId in schemeIds:
Packit 6978fb
        if self.entryId.get_text() == thisSchemeId or self.entryName.get_text() == self.schemeManager.get_scheme(thisSchemeId).get_name():
Packit 6978fb
Packit 6978fb
          text = 'There was a problem saving the scheme' \
Packit 6978fb
            '\n\nYou have choosen to create a new scheme' \
Packit 6978fb
            '\nbut the Name or ID you are using is being used already.' \
Packit 6978fb
            '\n\nPlease be sure to choose a Name and ID that are not already in use.\n'
Packit 6978fb
          message_dialog(Gtk.MessageType.ERROR, text, parent=self.window,
Packit 6978fb
            buttons=Gtk.ButtonsType.NONE,
Packit 6978fb
            additional_buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
Packit 6978fb
Packit 6978fb
          return
Packit 6978fb
Packit 6978fb
      nameOrIdChange = True
Packit 6978fb
Packit 6978fb
  
Packit 6978fb
    # attempt to save to ~/.local/share/gedit/styles/
Packit 6978fb
    stylesDir = os.path.join(GLib.get_user_data_dir(), "gedit", "styles")
Packit 6978fb
      
Packit 6978fb
    # if the file name or ID did not change, and they are using a local file, save it there
Packit 6978fb
    if (not nameOrIdChange and
Packit 6978fb
        os.access(inFile, os.W_OK) and
Packit 6978fb
        os.path.dirname(inFile) == stylesDir and
Packit 6978fb
        (str(os.path.dirname(inFile)) != tempDirectory)):
Packit 6978fb
Packit 6978fb
      outFile = inFile
Packit 6978fb
      
Packit 6978fb
    # else, designate a new file
Packit 6978fb
    else:
Packit 6978fb
      
Packit 6978fb
      if not os.path.isdir(stylesDir):
Packit 6978fb
        try:
Packit 6978fb
          os.makedirs(stylesDir)
Packit 6978fb
        except:
Packit 6978fb
          pass
Packit 6978fb
Packit 6978fb
      if (os.access(stylesDir, os.W_OK)):
Packit 6978fb
        outFile = os.path.join(stylesDir, self.entryId.get_text() + '.xml')
Packit 6978fb
Packit 6978fb
Packit 6978fb
    if outFile:
Packit 6978fb
Packit 6978fb
      # make sure the name/ID to not refer to a system scheme that is not writable
Packit 6978fb
      if inFile != outFile:
Packit 6978fb
Packit 6978fb
        schemeIds = self.schemeManager.get_scheme_ids()
Packit 6978fb
Packit 6978fb
        for thisSchemeId in schemeIds:
Packit 6978fb
          if self.entryId.get_text() == thisSchemeId or self.entryName.get_text() == self.schemeManager.get_scheme(thisSchemeId).get_name():
Packit 6978fb
Packit 6978fb
            text = 'There was a problem saving the scheme' \
Packit 6978fb
              '\n\nYou do not have permission to overwrite the scheme you have choosen.' \
Packit 6978fb
              '\nInstead a copy will be created.' \
Packit 6978fb
              '\n\nPlease be sure to choose a Name and ID that are not already in use.\n'
Packit 6978fb
            message_dialog(Gtk.MessageType.ERROR, text, parent=self.window,
Packit 6978fb
              buttons=Gtk.ButtonsType.NONE,
Packit 6978fb
              additional_buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
Packit 6978fb
Packit 6978fb
            return
Packit 6978fb
Packit 6978fb
      # write the file. complain if it fails to save
Packit 6978fb
      if not self.write_scheme(outFile, self.entryId.get_text(), self.entryName.get_text()):
Packit 6978fb
        message_dialog(Gtk.MessageType.ERROR, 'Error saving theme',
Packit 6978fb
          parent=self.window, buttons=Gtk.ButtonsType.NONE,
Packit 6978fb
          additional_buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
Packit 6978fb
          
Packit 6978fb
      else:
Packit 6978fb
        self.schemeManager.force_rescan()
Packit 6978fb
        updatedScheme = self.schemeManager.get_scheme(self.entryId.get_text())
Packit 6978fb
Packit 6978fb
        s = Gio.Settings('org.gnome.gedit.preferences.editor')
Packit 6978fb
        s.set_string('scheme', self.entryId.get_text())
Packit 6978fb
Packit 6978fb
        # update the view in all open documents
Packit 6978fb
        for thisDoc in self.geditApp.get_default().get_documents():
Packit 6978fb
          thisDoc.set_style_scheme(updatedScheme)
Packit 6978fb
Packit 6978fb
    else:
Packit 6978fb
      message_dialog(Gtk.MessageType.ERROR, 'Error saving theme',
Packit 6978fb
        buttons=Gtk.ButtonsType.NONE, parent=self.window,
Packit 6978fb
        additional_buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
Packit 6978fb
Packit 6978fb
    self.schemeManager.set_search_path(self.schemeManagerOrigSearchPath)
Packit 6978fb
    self.window.destroy()
Packit 6978fb
Packit 6978fb
  def load_scheme(self, schemeIdOrFile):
Packit 6978fb
    """ Load a scheme from a file or an existing scheme ID """
Packit 6978fb
Packit 6978fb
    if os.path.isfile(schemeIdOrFile):
Packit 6978fb
      
Packit 6978fb
      directory = os.path.dirname(schemeIdOrFile)
Packit 6978fb
    
Packit 6978fb
      if directory not in self.schemeManager.get_search_path():
Packit 6978fb
        self.schemeManager.prepend_search_path(directory)
Packit 6978fb
      
Packit 6978fb
      fp = open(schemeIdOrFile, 'r')
Packit 6978fb
      xmlTree = ET.parse(fp)
Packit 6978fb
      fp.close()
Packit 6978fb
Packit 6978fb
      if xmlTree.getroot().tag == 'style-scheme':
Packit 6978fb
        thisScheme = self.schemeManager.get_scheme(xmlTree.getroot().attrib['id'])
Packit 6978fb
      
Packit 6978fb
      if thisScheme == None:
Packit 6978fb
        return False
Packit 6978fb
        
Packit 6978fb
      testFilename = thisScheme.get_filename()
Packit 6978fb
      
Packit 6978fb
      if testFilename != schemeIdOrFile:
Packit 6978fb
        # there must have been some conflict, since it opened the wrong file
Packit 6978fb
Packit 6978fb
        text = 'There was a problem opening the file' \
Packit 6978fb
          '\n\nYou appear to have schemes with the same IDs in different directories\n'
Packit 6978fb
        message_dialog(Gtk.MessageType.ERROR, text,
Packit 6978fb
          parent=self.window, buttons=Gtk.ButtonsType.NONE,
Packit 6978fb
          additional_buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
Packit 6978fb
        
Packit 6978fb
        return False
Packit 6978fb
        
Packit 6978fb
      self.origSchemeFile = schemeIdOrFile
Packit 6978fb
Packit 6978fb
    else:
Packit 6978fb
Packit 6978fb
      thisScheme = self.schemeManager.get_scheme(schemeIdOrFile)
Packit 6978fb
    
Packit 6978fb
      if thisScheme == None:
Packit 6978fb
        return False
Packit 6978fb
    
Packit 6978fb
    self.currentScheme = thisScheme
Packit 6978fb
    
Packit 6978fb
    self.entryName.set_text( thisScheme.get_name() )
Packit 6978fb
    self.entryAuthor.set_text(', '.join(thisScheme.get_authors()))
Packit 6978fb
    self.entryDescription.set_text(thisScheme.get_description())
Packit 6978fb
    self.entryId.set_text(thisScheme.get_id())
Packit 6978fb
    
Packit 6978fb
    # get all the style elements
Packit 6978fb
    # since there are no API calls to do this, we parse the XML file for now
Packit 6978fb
    # also works around this https://bugzilla.gnome.org/show_bug.cgi?id=667194
Packit 6978fb
    self.origSchemeFile = self.currentScheme.get_filename()
Packit 6978fb
    
Packit 6978fb
    fp = open(self.origSchemeFile, 'r')
Packit 6978fb
    xmlTree = ET.parse(fp)
Packit 6978fb
    fp.close()
Packit 6978fb
    styleElements = xmlTree.findall('style')
Packit 6978fb
    
Packit 6978fb
    self.dictAllStyles.clear()
Packit 6978fb
    for styleElement in styleElements:
Packit 6978fb
      thisStyle = self.currentScheme.get_style(styleElement.attrib['name'])
Packit 6978fb
      styleProps = Props()
Packit 6978fb
      
Packit 6978fb
      styleProps.from_gtk_source_style(thisStyle)
Packit 6978fb
      
Packit 6978fb
      self.dictAllStyles[styleElement.attrib['name']] = styleProps;
Packit 6978fb
            
Packit 6978fb
    self.sourceBuffer.set_style_scheme(self.currentScheme);
Packit 6978fb
    
Packit 6978fb
    # set up temp file so the sample view can be updated
Packit 6978fb
    self.tempSchemeId = thisScheme.get_id() + '_temp'
Packit 6978fb
    self.tempSchemeName = thisScheme.get_name() + '_temp'
Packit 6978fb
    self.tempSchemeFile = tempfile.gettempdir() + '/' + self.tempSchemeId + '.xml'
Packit 6978fb
    
Packit 6978fb
    return True
Packit 6978fb
    
Packit 6978fb
  def clear_and_disable_style_buttons(self):
Packit 6978fb
Packit 6978fb
    self.colorbuttonForeground.set_color(self.colorBlack)
Packit 6978fb
    self.colorbuttonBackground.set_color(self.colorBlack)
Packit 6978fb
    self.colorbuttonForeground.set_sensitive(False)
Packit 6978fb
    self.checkbuttonForeground.set_active(False)
Packit 6978fb
    self.colorbuttonBackground.set_sensitive(False)
Packit 6978fb
    self.checkbuttonBackground.set_active(False)
Packit 6978fb
    
Packit 6978fb
    self.togglebuttonItalic.set_active(False)
Packit 6978fb
    self.togglebuttonBold.set_active(False)
Packit 6978fb
    self.togglebuttonStrikethrough.set_active(False)
Packit 6978fb
    self.togglebuttonUnderline.set_active(False)
Packit 6978fb
    
Packit 6978fb
    self.resetButton.set_sensitive(False)
Packit 6978fb
    
Packit 6978fb
  def update_sample_view(self):
Packit 6978fb
    """
Packit 6978fb
    Update the sample shown in the GUI.
Packit 6978fb
    To do this we must write the scheme to disk and reload it from there.
Packit 6978fb
    """
Packit 6978fb
    
Packit 6978fb
    # write it to disk
Packit 6978fb
    self.write_scheme(self.tempSchemeFile, self.tempSchemeId, self.tempSchemeName)
Packit 6978fb
    
Packit 6978fb
    # and reload it from disk
Packit 6978fb
    self.schemeManager.force_rescan()
Packit 6978fb
    
Packit 6978fb
    newScheme = self.schemeManager.get_scheme(self.tempSchemeId)
Packit 6978fb
    self.sourceBuffer.set_style_scheme(newScheme);
Packit 6978fb
    
Packit 6978fb
  def write_scheme(self, location, schemeId, schemeName):
Packit 6978fb
    """Write the scheme to disk
Packit 6978fb
    
Packit 6978fb
    location -- the file location to write to
Packit 6978fb
    schemeId -- the ID of the scheme
Packit 6978fb
    """
Packit 6978fb
Packit 6978fb
    output = '<style-scheme name="'+ schemeName + '" id="'+ schemeId +'" version="1.0">\n'
Packit 6978fb
    
Packit 6978fb
    output += '  <author>'+ self.entryAuthor.get_text() +'</author>\n'
Packit 6978fb
    output += '  <description>'+ self.entryDescription.get_text() +'</description>\n\n'
Packit 6978fb
    
Packit 6978fb
    for k, v in list(self.dictAllStyles.items()):
Packit 6978fb
      output += '  
Packit 6978fb
      
Packit 6978fb
      if (v.foreground): output += 'foreground="'+ v.foreground +'" '
Packit 6978fb
      if (v.background): output += 'background="'+ v.background +'" '
Packit 6978fb
      if (v.italic): output += 'italic="true" '
Packit 6978fb
      if (v.bold): output += 'bold="true" '
Packit 6978fb
      if (v.underline):  output += 'underline="true" '
Packit 6978fb
      if (v.strikethrough):  output += 'strikethrough="true" '
Packit 6978fb
      
Packit 6978fb
      output += '/>\n'
Packit 6978fb
    
Packit 6978fb
    output  += '</style-scheme>\n'
Packit 6978fb
    
Packit 6978fb
    try:
Packit 6978fb
      fp = open(location, 'w')
Packit 6978fb
      fp.write(output)
Packit 6978fb
      fp.close()
Packit 6978fb
    except:
Packit 6978fb
      return False
Packit 6978fb
Packit 6978fb
    return True
Packit 6978fb
    
Packit 6978fb
  def on_reset_clicked(self, param):
Packit 6978fb
    
Packit 6978fb
    if self.selectedStyleId in self.dictAllStyles:
Packit 6978fb
    
Packit 6978fb
      del self.dictAllStyles[self.selectedStyleId]
Packit 6978fb
    
Packit 6978fb
      # reset the GUI
Packit 6978fb
      self.clear_and_disable_style_buttons()
Packit 6978fb
      
Packit 6978fb
      self.update_sample_view()
Packit 6978fb
      
Packit 6978fb
  def on_background_toggled(self, param):
Packit 6978fb
    
Packit 6978fb
    # user is enabling color selection
Packit 6978fb
    if param.get_active():
Packit 6978fb
      self.colorbuttonBackground.set_sensitive(True)
Packit 6978fb
      self.colorbuttonBackground.activate()
Packit 6978fb
      
Packit 6978fb
      self.resetButton.set_sensitive(True)
Packit 6978fb
      
Packit 6978fb
    # user is disabling color selection
Packit 6978fb
    else:
Packit 6978fb
      self.colorbuttonBackground.set_sensitive(False)
Packit 6978fb
      
Packit 6978fb
      try:
Packit 6978fb
        self.dictAllStyles[self.selectedStyleId].background = None;
Packit 6978fb
        
Packit 6978fb
        self.clear_style_if_empty(self.selectedStyleId)
Packit 6978fb
          
Packit 6978fb
      except:
Packit 6978fb
        pass
Packit 6978fb
Packit 6978fb
      self.update_sample_view()
Packit 6978fb
      
Packit 6978fb
  def on_foreground_toggled(self, param):
Packit 6978fb
    
Packit 6978fb
    # user is enabling color selection
Packit 6978fb
    if param.get_active():
Packit 6978fb
      self.colorbuttonForeground.set_sensitive(True)
Packit 6978fb
      self.colorbuttonForeground.activate()
Packit 6978fb
Packit 6978fb
      self.resetButton.set_sensitive(True)
Packit 6978fb
      
Packit 6978fb
    # user is disabling color selection
Packit 6978fb
    else:
Packit 6978fb
      self.colorbuttonForeground.set_sensitive(False)
Packit 6978fb
      
Packit 6978fb
      try:
Packit 6978fb
        self.dictAllStyles[self.selectedStyleId].foreground = None;
Packit 6978fb
        self.clear_style_if_empty(self.selectedStyleId)
Packit 6978fb
      except:
Packit 6978fb
        pass
Packit 6978fb
        
Packit 6978fb
      self.update_sample_view()
Packit 6978fb
  
Packit 6978fb
  def clear_style_if_empty(self, styleId):
Packit 6978fb
    """ Check to see if there are no attribtes set for a style. If so disable the
Packit 6978fb
      "Clear" button and remove the style entry from the schema file.
Packit 6978fb
    """
Packit 6978fb
    
Packit 6978fb
    if styleId not in self.dictAllStyles:
Packit 6978fb
      return
Packit 6978fb
Packit 6978fb
    if (self.dictAllStyles[self.selectedStyleId].is_clear()):
Packit 6978fb
      del self.dictAllStyles[self.selectedStyleId]
Packit 6978fb
      self.clear_and_disable_style_buttons()
Packit 6978fb
  
Packit 6978fb
  
Packit 6978fb
  def on_style_changed(self, data):
Packit 6978fb
    """ Handles button clicks for foreground color, background color, 
Packit 6978fb
      bold, italic, underline, or strikethrough.
Packit 6978fb
    """
Packit 6978fb
        
Packit 6978fb
    if self.selectedStyleId not in self.dictAllStyles:
Packit 6978fb
      self.dictAllStyles[self.selectedStyleId] = Props()
Packit 6978fb
    
Packit 6978fb
    cScale = 255.0/65535.0
Packit 6978fb
    
Packit 6978fb
    if data == self.colorbuttonBackground:
Packit 6978fb
      color = data.get_color()
Packit 6978fb
      self.dictAllStyles[self.selectedStyleId].background = ('#%02x%02x%02x' %
Packit 6978fb
        (color.red * cScale, color.green * cScale, color.blue * cScale))
Packit 6978fb
    
Packit 6978fb
    elif data == self.colorbuttonForeground:
Packit 6978fb
      color = data.get_color()
Packit 6978fb
      self.dictAllStyles[self.selectedStyleId].foreground = ('#%02x%02x%02x' %
Packit 6978fb
        (color.red * cScale, color.green * cScale, color.blue * cScale))
Packit 6978fb
    
Packit 6978fb
    elif data == self.togglebuttonBold:
Packit 6978fb
      self.dictAllStyles[self.selectedStyleId].bold = data.get_active()
Packit 6978fb
      
Packit 6978fb
    elif data == self.togglebuttonItalic:
Packit 6978fb
      self.dictAllStyles[self.selectedStyleId].italic = data.get_active()
Packit 6978fb
    
Packit 6978fb
    elif data == self.togglebuttonUnderline:
Packit 6978fb
      self.dictAllStyles[self.selectedStyleId].underline = data.get_active()
Packit 6978fb
    
Packit 6978fb
    elif data == self.togglebuttonStrikethrough:
Packit 6978fb
      self.dictAllStyles[self.selectedStyleId].strikethrough = data.get_active()
Packit 6978fb
    
Packit 6978fb
    # make sure the "Clear" button is enabled if something gets turned on
Packit 6978fb
    try:
Packit 6978fb
      if data.get_active() == True:
Packit 6978fb
        self.resetButton.set_sensitive(True)
Packit 6978fb
    except: pass
Packit 6978fb
    
Packit 6978fb
    self.clear_style_if_empty(self.selectedStyleId)
Packit 6978fb
    
Packit 6978fb
    self.update_sample_view()
Packit 6978fb
    
Packit 6978fb
  def on_style_selected(self, selection):
Packit 6978fb
    model, treeiter = selection.get_selected()
Packit 6978fb
Packit 6978fb
    # handle the special case for when the styles get cleared since the signal activates
Packit 6978fb
    if treeiter == None:
Packit 6978fb
      return
Packit 6978fb
    
Packit 6978fb
    self.selectedStyleId = self.selectedLanguageId + ':' + model[treeiter][0]
Packit 6978fb
Packit 6978fb
    # handle the special case for GUI styles
Packit 6978fb
    if self.selectedStyleId not in self.dictAllStyles and self.selectedLanguageId == 'def':
Packit 6978fb
      self.selectedStyleId = model[treeiter][0]
Packit 6978fb
    
Packit 6978fb
    # block all the toggle handlers so they dont get triggered
Packit 6978fb
    self.togglebuttonItalic.handler_block(self.togglebuttonItalicHandler)
Packit 6978fb
    self.togglebuttonBold.handler_block(self.togglebuttonBoldHandler)
Packit 6978fb
    self.togglebuttonUnderline.handler_block(self.togglebuttonUnderlineHandler)
Packit 6978fb
    self.togglebuttonStrikethrough.handler_block(self.togglebuttonStrikethroughHandler)
Packit 6978fb
    self.checkbuttonBackground.handler_block(self.checkbuttonBackgroundHandler)
Packit 6978fb
    self.checkbuttonForeground.handler_block(self.checkbuttonForegroundHandler)
Packit 6978fb
    
Packit 6978fb
    if self.selectedStyleId in self.dictAllStyles:
Packit 6978fb
      
Packit 6978fb
      thisStyle = self.dictAllStyles[self.selectedStyleId]
Packit 6978fb
      
Packit 6978fb
      # handle foreground and background colors
Packit 6978fb
Packit 6978fb
      if thisStyle.foreground:
Packit 6978fb
        self.colorbuttonForeground.set_color(Gdk.color_parse(thisStyle.foreground))
Packit 6978fb
        self.colorbuttonForeground.set_sensitive(True)
Packit 6978fb
        self.checkbuttonForeground.set_active(True)
Packit 6978fb
      else:
Packit 6978fb
        self.colorbuttonForeground.set_color(self.colorBlack)
Packit 6978fb
        self.colorbuttonForeground.set_sensitive(False)
Packit 6978fb
        self.checkbuttonForeground.set_active(False)
Packit 6978fb
Packit 6978fb
      if thisStyle.background:
Packit 6978fb
        self.colorbuttonBackground.set_color(Gdk.color_parse(thisStyle.background))
Packit 6978fb
        self.colorbuttonBackground.set_sensitive(True)
Packit 6978fb
        self.checkbuttonBackground.set_active(True)
Packit 6978fb
      else:
Packit 6978fb
        self.colorbuttonBackground.set_color(self.colorBlack)
Packit 6978fb
        self.colorbuttonBackground.set_sensitive(False)
Packit 6978fb
        self.checkbuttonBackground.set_active(False)
Packit 6978fb
        
Packit 6978fb
      # handle text styling
Packit 6978fb
Packit 6978fb
      self.togglebuttonItalic.set_active(thisStyle.italic)
Packit 6978fb
      self.togglebuttonBold.set_active(thisStyle.bold)
Packit 6978fb
      self.togglebuttonStrikethrough.set_active(thisStyle.strikethrough)
Packit 6978fb
      self.togglebuttonUnderline.set_active(thisStyle.underline)
Packit 6978fb
      self.resetButton.set_sensitive(True)
Packit 6978fb
      
Packit 6978fb
    # if style does not exist, set to default GUI values
Packit 6978fb
    else:
Packit 6978fb
      self.clear_and_disable_style_buttons()
Packit 6978fb
      
Packit 6978fb
    # unblock toggle handlers so the user can do stuff
Packit 6978fb
    self.togglebuttonItalic.handler_unblock(self.togglebuttonItalicHandler)
Packit 6978fb
    self.togglebuttonBold.handler_unblock(self.togglebuttonBoldHandler)
Packit 6978fb
    self.togglebuttonUnderline.handler_unblock(self.togglebuttonUnderlineHandler)
Packit 6978fb
    self.togglebuttonStrikethrough.handler_unblock(self.togglebuttonStrikethroughHandler)
Packit 6978fb
    self.checkbuttonBackground.handler_unblock(self.checkbuttonBackgroundHandler)
Packit 6978fb
    self.checkbuttonForeground.handler_unblock(self.checkbuttonForegroundHandler)
Packit 6978fb
  
Packit 6978fb
  def on_language_selected(self, combo):
Packit 6978fb
Packit 6978fb
    tree_iter = combo.get_active_iter()
Packit 6978fb
    if tree_iter != None:
Packit 6978fb
      model = combo.get_model()
Packit 6978fb
      self.selectedLanguageName = model[tree_iter][0]
Packit 6978fb
      self.selectedLanguageId = self.langMapNameToId[self.selectedLanguageName]
Packit 6978fb
      
Packit 6978fb
      self.liststoreStyles.clear()
Packit 6978fb
      
Packit 6978fb
      # remove the language namespace thing from the style name
Packit 6978fb
      removeLen = len(self.selectedLanguageId) + 1
Packit 6978fb
      
Packit 6978fb
      thisLanguage = self.languageManager.get_language(self.selectedLanguageId)
Packit 6978fb
      
Packit 6978fb
      if thisLanguage != None:
Packit 6978fb
      
Packit 6978fb
        styleIds = thisLanguage.get_style_ids() # TODO: why is 'gtk-doc.lang' throwing a warning?
Packit 6978fb
        
Packit 6978fb
        styleIds.sort() # make the styles list alphabetical
Packit 6978fb
        
Packit 6978fb
        if self.selectedLanguageId == 'def':
Packit 6978fb
          for styleId in self.guiStyleIds:
Packit 6978fb
            self.liststoreStyles.append([styleId])
Packit 6978fb
        
Packit 6978fb
        for styleId in styleIds:
Packit 6978fb
          self.liststoreStyles.append([styleId[removeLen:]])
Packit 6978fb
      
Packit 6978fb
      # select the first style in the list
Packit 6978fb
      treeIter = self.treeviewStyles.get_model().get_iter_first()
Packit 6978fb
      
Packit 6978fb
      if treeIter != None:  # make sure the list is not empty since some languages have no styles
Packit 6978fb
        self.treeviewStylesSelection.select_iter(treeIter)
Packit 6978fb
        model = self.treeviewStyles.get_model()
Packit 6978fb
        self.selectedStyleId = model[treeIter][0]
Packit 6978fb
      
Packit 6978fb
      # update the sample view
Packit 6978fb
      if self.selectedLanguageId in samples:
Packit 6978fb
        self.sourceBuffer.set_language(thisLanguage);
Packit 6978fb
        self.sourceBuffer.set_text(samples[self.selectedLanguageId])
Packit 6978fb
        self.labelSample.set_text(self.selectedLanguageName + ' sample')
Packit 6978fb
      elif self.bufferLanguageId in samples:
Packit 6978fb
        self.sourceBuffer.set_language(self.bufferLanguage)
Packit 6978fb
        self.sourceBuffer.set_text(samples[self.bufferLanguageId])
Packit 6978fb
        self.labelSample.set_text(self.bufferLanguageName + ' sample')
Packit 6978fb
      else:
Packit 6978fb
        self.sourceBuffer.set_language(self.defaultLanguage);
Packit 6978fb
        self.sourceBuffer.set_text(samples[self.defaultLanguageId])
Packit 6978fb
        self.labelSample.set_text(self.defaultLanguageName + ' sample')
Packit 6978fb
Packit 6978fb
Packit 6978fb
Packit 6978fb
def message_dialog(dialog_type, shortMsg, longMsg=None, parent=None,
Packit 6978fb
                  buttons=Gtk.ButtonsType.OK, additional_buttons=None):
Packit 6978fb
Packit 6978fb
  d = Gtk.MessageDialog(parent=parent, flags=Gtk.DialogFlags.MODAL,
Packit 6978fb
    type=dialog_type, buttons=buttons)
Packit 6978fb
Packit 6978fb
  if additional_buttons:
Packit 6978fb
    d.add_buttons(*additional_buttons)
Packit 6978fb
Packit 6978fb
  d.set_markup(shortMsg)
Packit 6978fb
Packit 6978fb
  if longMsg:
Packit 6978fb
    if isinstance(longMsg, Gtk.Widget):
Packit 6978fb
      widget = longMsg
Packit 6978fb
    elif isinstance(longMsg, str):
Packit 6978fb
      widget = Gtk.Label()
Packit 6978fb
      widget.set_markup(longMsg)
Packit 6978fb
    else:
Packit 6978fb
      raise TypeError('"longMsg" must be a Gtk.Widget or a string')
Packit 6978fb
    
Packit 6978fb
    expander = Gtk.Expander(label = 'Click here for details')
Packit 6978fb
    expander.set_border_width(6)
Packit 6978fb
    expander.add(widget)
Packit 6978fb
    d.vbox.pack_end(expander, True, True, 0)
Packit 6978fb
      
Packit 6978fb
  d.show_all()
Packit 6978fb
  response = d.run()
Packit 6978fb
  d.destroy()
Packit 6978fb
  return response
Packit 6978fb