Started to add support for Google protobuf protocol files.

Sun, 12 Nov 2017 19:42:02 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 12 Nov 2017 19:42:02 +0100
changeset 5968
c5112b5cb7a9
parent 5967
da72832f7c22
child 5969
584c21b6587a

Started to add support for Google protobuf protocol files.

E5XML/ProjectReader.py file | annotate | diff | comparison | revisions
E5XML/ProjectWriter.py file | annotate | diff | comparison | revisions
Preferences/ConfigurationDialog.py file | annotate | diff | comparison | revisions
Preferences/ConfigurationPages/ProjectBrowserPage.py file | annotate | diff | comparison | revisions
Preferences/ConfigurationPages/ProjectBrowserPage.ui file | annotate | diff | comparison | revisions
Preferences/ConfigurationPages/ProtobufPage.py file | annotate | diff | comparison | revisions
Preferences/ConfigurationPages/ProtobufPage.ui file | annotate | diff | comparison | revisions
Preferences/ProgramsDialog.py file | annotate | diff | comparison | revisions
Preferences/__init__.py file | annotate | diff | comparison | revisions
Project/Project.py file | annotate | diff | comparison | revisions
Project/ProjectBrowser.py file | annotate | diff | comparison | revisions
Project/ProjectBrowserFlags.py file | annotate | diff | comparison | revisions
Project/ProjectBrowserModel.py file | annotate | diff | comparison | revisions
Project/ProjectProtocolsBrowser.py file | annotate | diff | comparison | revisions
UI/Browser.py file | annotate | diff | comparison | revisions
UI/BrowserModel.py file | annotate | diff | comparison | revisions
UI/UserInterface.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
icons/default/protobuf.png file | annotate | diff | comparison | revisions
--- a/E5XML/ProjectReader.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/E5XML/ProjectReader.py	Sun Nov 12 19:42:02 2017 +0100
@@ -15,6 +15,7 @@
 import Utilities
 
 
+# TODO: add support for 'PROTOCOLS' (analog INTERFACES)
 class ProjectReader(XMLStreamReaderBase):
     """
     Class for reading an XML project file.
--- a/E5XML/ProjectWriter.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/E5XML/ProjectWriter.py	Sun Nov 12 19:42:02 2017 +0100
@@ -20,6 +20,7 @@
 import Utilities
 
 
+# TODO: add support for 'PROTOCOLS' (analog INTERFACES)
 class ProjectWriter(XMLStreamWriterBase):
     """
     Class implementing the writer class for writing an XML project file.
--- a/Preferences/ConfigurationDialog.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Preferences/ConfigurationDialog.py	Sun Nov 12 19:42:02 2017 +0100
@@ -179,6 +179,9 @@
                 "printerPage":
                 [self.tr("Printer"), "preferences-printer.png",
                  "PrinterPage", None, None],
+                "protobufPage":
+                [self.tr("Protobuf"), "protobuf.png",
+                 "ProtobufPage", None, None],
                 "pythonPage":
                 [self.tr("Python"), "preferences-python.png",
                  "PythonPage", None, None],
--- a/Preferences/ConfigurationPages/ProjectBrowserPage.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Preferences/ConfigurationPages/ProjectBrowserPage.py	Sun Nov 12 19:42:02 2017 +0100
@@ -93,7 +93,7 @@
         """
         from Project.ProjectBrowserFlags import SourcesBrowserFlag, \
             FormsBrowserFlag, ResourcesBrowserFlag, TranslationsBrowserFlag, \
-            InterfacesBrowserFlag, OthersBrowserFlag
+            InterfacesBrowserFlag, OthersBrowserFlag, ProtocolsBrowserFlag
         
         flags = 0
         if self.sourcesBrowserCheckBox.isChecked():
@@ -108,6 +108,8 @@
             flags |= InterfacesBrowserFlag
         if self.othersBrowserCheckBox.isChecked():
             flags |= OthersBrowserFlag
+        if self.protocolsBrowserCheckBox.isChecked():
+            flags |= ProtocolsBrowserFlag
         
         self.__projectBrowserFlags[projectType] = flags
     
@@ -120,7 +122,7 @@
         """
         from Project.ProjectBrowserFlags import SourcesBrowserFlag, \
             FormsBrowserFlag, ResourcesBrowserFlag, TranslationsBrowserFlag, \
-            InterfacesBrowserFlag, OthersBrowserFlag
+            InterfacesBrowserFlag, OthersBrowserFlag, ProtocolsBrowserFlag
         
         flags = self.__projectBrowserFlags[projectType]
         
@@ -132,6 +134,7 @@
         self.interfacesBrowserCheckBox.setChecked(
             flags & InterfacesBrowserFlag)
         self.othersBrowserCheckBox.setChecked(flags & OthersBrowserFlag)
+        self.protocolsBrowserCheckBox.setChecked(flags & ProtocolsBrowserFlag)
     
     @pyqtSlot(int)
     def on_projectTypeCombo_activated(self, index):
--- a/Preferences/ConfigurationPages/ProjectBrowserPage.ui	Sat Nov 11 18:47:09 2017 +0100
+++ b/Preferences/ConfigurationPages/ProjectBrowserPage.ui	Sun Nov 12 19:42:02 2017 +0100
@@ -10,7 +10,7 @@
     <height>497</height>
    </rect>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
+  <layout class="QVBoxLayout" name="verticalLayout_2">
    <item>
     <widget class="QLabel" name="headerLabel">
      <property name="text">
@@ -81,7 +81,7 @@
      <property name="title">
       <string>Visible Project Browsers</string>
      </property>
-     <layout class="QVBoxLayout">
+     <layout class="QVBoxLayout" name="verticalLayout">
       <item>
        <layout class="QHBoxLayout">
         <item>
@@ -107,7 +107,7 @@
        </layout>
       </item>
       <item>
-       <layout class="QGridLayout">
+       <layout class="QGridLayout" name="gridLayout">
         <item row="0" column="0">
          <widget class="QCheckBox" name="sourcesBrowserCheckBox">
           <property name="toolTip">
@@ -119,12 +119,12 @@
          </widget>
         </item>
         <item row="0" column="1">
-         <widget class="QCheckBox" name="translationsBrowserCheckBox">
+         <widget class="QCheckBox" name="interfacesBrowserCheckBox">
           <property name="toolTip">
-           <string>Select to show the translations browser</string>
+           <string>Select to show the interfaces (IDL) browser</string>
           </property>
           <property name="text">
-           <string>Translations Browser</string>
+           <string>Interfaces (IDL) Browser</string>
           </property>
          </widget>
         </item>
@@ -139,12 +139,12 @@
          </widget>
         </item>
         <item row="1" column="1">
-         <widget class="QCheckBox" name="interfacesBrowserCheckBox">
+         <widget class="QCheckBox" name="protocolsBrowserCheckBox">
           <property name="toolTip">
-           <string>Select to show the interfaces (IDL) browser</string>
+           <string>Select to show the protocols (protobuf) browser</string>
           </property>
           <property name="text">
-           <string>Interfaces (IDL) Browser</string>
+           <string>Protocols (protobuf) Browser</string>
           </property>
          </widget>
         </item>
@@ -168,6 +168,16 @@
           </property>
          </widget>
         </item>
+        <item row="3" column="0">
+         <widget class="QCheckBox" name="translationsBrowserCheckBox">
+          <property name="toolTip">
+           <string>Select to show the translations browser</string>
+          </property>
+          <property name="text">
+           <string>Translations Browser</string>
+          </property>
+         </widget>
+        </item>
        </layout>
       </item>
      </layout>
@@ -236,6 +246,7 @@
   <tabstop>resourcesBrowserCheckBox</tabstop>
   <tabstop>translationsBrowserCheckBox</tabstop>
   <tabstop>interfacesBrowserCheckBox</tabstop>
+  <tabstop>protocolsBrowserCheckBox</tabstop>
   <tabstop>othersBrowserCheckBox</tabstop>
   <tabstop>followEditorCheckBox</tabstop>
   <tabstop>followCursorLineCheckBox</tabstop>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Preferences/ConfigurationPages/ProtobufPage.py	Sun Nov 12 19:42:02 2017 +0100
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the protobuf configuration page.
+"""
+
+from __future__ import unicode_literals
+
+from E5Gui.E5PathPicker import E5PathPickerModes
+
+from .ConfigurationPageBase import ConfigurationPageBase
+from .Ui_ProtobufPage import Ui_ProtobufPage
+
+import Preferences
+
+
+class ProtobufPage(ConfigurationPageBase, Ui_ProtobufPage):
+    """
+    Class implementing the protobuf configuration page.
+    """
+    def __init__(self):
+        """
+        Constructor
+        """
+        super(ProtobufPage, self).__init__()
+        self.setupUi(self)
+        self.setObjectName("ProtobufPage")
+        
+        self.protocPicker.setMode(E5PathPickerModes.OpenFileMode)
+        self.protocPicker.setToolTip(self.tr(
+            "Press to select the Protobuf compiler via a file selection"
+            " dialog."))
+        
+        # set initial values
+        self.protocPicker.setText(Preferences.getProtobuf("protoc"))
+        
+    def save(self):
+        """
+        Public slot to save the protobuf configuration.
+        """
+        Preferences.setProtobuf("protoc", self.protocPicker.text())
+    
+
+def create(dlg):
+    """
+    Module function to create the configuration page.
+    
+    @param dlg reference to the configuration dialog
+    @return reference to the instantiated page (ConfigurationPageBase)
+    """
+    page = ProtobufPage()
+    return page
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Preferences/ConfigurationPages/ProtobufPage.ui	Sun Nov 12 19:42:02 2017 +0100
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProtobufPage</class>
+ <widget class="QWidget" name="ProtobufPage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>589</width>
+    <height>490</height>
+   </rect>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_3">
+   <item>
+    <widget class="QLabel" name="headerLabel">
+     <property name="text">
+      <string>&lt;b&gt;Configure Protobuf support&lt;/b&gt;</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line13">
+     <property name="frameShape">
+      <enum>QFrame::HLine</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Sunken</enum>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="title">
+      <string>Protobuf Compiler</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <widget class="E5PathPicker" name="protocPicker" native="true">
+        <property name="focusPolicy">
+         <enum>Qt::StrongFocus</enum>
+        </property>
+        <property name="toolTip">
+         <string>Enter the path to the protobuf compiler.</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="textLabel1_5">
+        <property name="text">
+         <string>&lt;b&gt;Note:&lt;/b&gt; Leave this entry empty to use the default value (protoc or protoc.exe).</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer>
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>81</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>E5PathPicker</class>
+   <extends>QWidget</extends>
+   <header>E5Gui/E5PathPicker.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
--- a/Preferences/ProgramsDialog.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Preferences/ProgramsDialog.py	Sun Nov 12 19:42:02 2017 +0100
@@ -197,13 +197,23 @@
             Utilities.isWindowsPlatform() and "rbrcc.exe" or "rbrcc",
             '-version', 'Ruby Resource Compiler', -1)
         
-        # 5. do the CORBA programs
+        # 5. do the CORBA and Protobuf programs
         # 5a. omniORB
         exe = Preferences.getCorba("omniidl")
+        if not exe:
+            exe = "omniidl"
         if Utilities.isWindowsPlatform():
             exe += ".exe"
         self.__createProgramEntry(
             self.tr("CORBA IDL Compiler"), exe, '-V', 'omniidl', -1)
+        # 5b. protobuf
+        exe = Preferences.getProtobuf("protoc")
+        if not exe:
+            exe = "protoc"
+        if Utilities.isWindowsPlatform():
+            exe += ".exe"
+        self.__createProgramEntry(
+            self.tr("Protobuf Compiler"), exe, '--version', 'libprotoc', -1)
         
         # 6. do the spell checking entry
         try:
--- a/Preferences/__init__.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Preferences/__init__.py	Sun Nov 12 19:42:02 2017 +0100
@@ -53,7 +53,7 @@
 
 from Project.ProjectBrowserFlags import SourcesBrowserFlag, FormsBrowserFlag, \
     ResourcesBrowserFlag, TranslationsBrowserFlag, InterfacesBrowserFlag, \
-    OthersBrowserFlag, AllBrowsersFlag
+    OthersBrowserFlag, ProtocolsBrowserFlag, AllBrowsersFlag
 
 try:
     from Helpviewer.FlashCookieManager.FlashCookieUtilities import \
@@ -780,54 +780,63 @@
             ResourcesBrowserFlag |
             TranslationsBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "Qt4C": (
             SourcesBrowserFlag |
             ResourcesBrowserFlag |
             TranslationsBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "PyQt5": (
             SourcesBrowserFlag |
             FormsBrowserFlag |
             ResourcesBrowserFlag |
             TranslationsBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "PyQt5C": (
             SourcesBrowserFlag |
             ResourcesBrowserFlag |
             TranslationsBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "E6Plugin": (
             SourcesBrowserFlag |
             FormsBrowserFlag |
             ResourcesBrowserFlag |
             TranslationsBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "Console": (
             SourcesBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "Other": (
             SourcesBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "PySide": (
             SourcesBrowserFlag |
             FormsBrowserFlag |
             ResourcesBrowserFlag |
             TranslationsBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
         "PySideC": (
             SourcesBrowserFlag |
             ResourcesBrowserFlag |
             TranslationsBrowserFlag |
             InterfacesBrowserFlag |
-            OthersBrowserFlag),
+            OthersBrowserFlag |
+            ProtocolsBrowserFlag),
     }
     
     # defaults for the project browser colour settings
@@ -1270,7 +1279,12 @@
     
     # defaults for corba related stuff
     corbaDefaults = {
-        "omniidl": "omniidl"
+        "omniidl": ""
+    }
+    
+    # defaults for protobuf related stuff
+    protobufDefaults = {
+        "protoc": ""
     }
     
     # defaults for user related stuff
@@ -3139,7 +3153,7 @@
 
 def getCorba(key, prefClass=Prefs):
     """
-    Module function to retrieve the various corba settings.
+    Module function to retrieve the various Corba settings.
     
     @param key the key of the value to get
     @param prefClass preferences class used as the storage area
@@ -3151,7 +3165,7 @@
 
 def setCorba(key, value, prefClass=Prefs):
     """
-    Module function to store the various corba settings.
+    Module function to store the various Corba settings.
     
     @param key the key of the setting to be set
     @param value the value to be set
@@ -3160,6 +3174,35 @@
     prefClass.settings.setValue("Corba/" + key, value)
     
 
+def getProtobuf(key, prefClass=Prefs):
+    """
+    Module function to retrieve the various protobuf settings.
+    
+    @param key the key of the value to get
+    @type str
+    @param prefClass preferences class used as the storage area
+    @type Prefs
+    @return the requested protobuf setting
+    @rtype any
+    """
+    return prefClass.settings.value(
+        "Protobuf/" + key, prefClass.protobufDefaults[key])
+    
+
+def setProtobuf(key, value, prefClass=Prefs):
+    """
+    Module function to store the various protobuf settings.
+    
+    @param key the key of the setting to be set
+    @type str
+    @param value the value to be set
+    @type any
+    @param prefClass preferences class used as the storage area
+    @type Prefs
+    """
+    prefClass.settings.setValue("Protobuf/" + key, value)
+    
+
 def getUser(key, prefClass=Prefs):
     """
     Module function to retrieve the various user settings.
--- a/Project/Project.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Project/Project.py	Sun Nov 12 19:42:02 2017 +0100
@@ -43,6 +43,7 @@
 import Utilities
 
 
+# TODO: add support for 'PROTOCOLS' (analog INTERFACES)
 class Project(QObject):
     """
     Class implementing the project management functionality.
@@ -428,6 +429,7 @@
             "FORMS": [],
             "RESOURCES": [],
             "INTERFACES": [],
+            "PROTOCOLS": [],
             "OTHERS": [],
             "TRANSLATIONS": [],
             "TRANSLATIONEXCEPTIONS": [],
--- a/Project/ProjectBrowser.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Project/ProjectBrowser.py	Sun Nov 12 19:42:02 2017 +0100
@@ -23,7 +23,7 @@
 
 from .ProjectBrowserFlags import SourcesBrowserFlag, FormsBrowserFlag, \
     ResourcesBrowserFlag, TranslationsBrowserFlag, InterfacesBrowserFlag, \
-    OthersBrowserFlag, AllBrowsersFlag
+    OthersBrowserFlag, ProtocolsBrowserFlag, AllBrowsersFlag
 
 
 class ProjectBrowser(E5TabWidget):
@@ -85,6 +85,7 @@
         from .ProjectResourcesBrowser import ProjectResourcesBrowser
         from .ProjectInterfacesBrowser import ProjectInterfacesBrowser
         from .ProjectOthersBrowser import ProjectOthersBrowser
+        from .ProjectProtocolsBrowser import ProjectProtocolsBrowser
         # sources browser
         self.psBrowser = ProjectSourcesBrowser(self.project)
         # forms browser
@@ -95,6 +96,8 @@
         self.ptBrowser = ProjectTranslationsBrowser(self.project)
         # interfaces (IDL) browser
         self.piBrowser = ProjectInterfacesBrowser(self.project)
+        # protocols (protobuf) browser
+        self.ppBrowser = ProjectProtocolsBrowser(self.project)
         # others browser
         self.poBrowser = ProjectOthersBrowser(self.project)
         
@@ -144,6 +147,14 @@
         self.project.projectPropertiesChanged.connect(
             self.piBrowser._initMenusAndVcs)
         
+        # connect the protocols (protobuf)  browser
+        self.project.projectClosed.connect(self.ppBrowser._projectClosed)
+        self.project.projectOpened.connect(self.ppBrowser._projectOpened)
+        self.project.newProject.connect(self.ppBrowser._newProject)
+        self.project.reinitVCS.connect(self.ppBrowser._initMenusAndVcs)
+        self.project.projectPropertiesChanged.connect(
+            self.ppBrowser._initMenusAndVcs)
+        
         # connect the others browser
         self.project.projectClosed.connect(self.poBrowser._projectClosed)
         self.project.projectOpened.connect(self.poBrowser._projectOpened)
@@ -209,6 +220,12 @@
                 UI.PixmapCache.getIcon("projectInterfaces.png"), '')
             self.setTabToolTip(index, self.piBrowser.windowTitle())
         
+        if browserFlags & ProtocolsBrowserFlag:
+            index = self.addTab(
+                self.ppBrowser,
+                UI.PixmapCache.getIcon("protobuf.png"), '')
+            self.setTabToolTip(index, self.ppBrowser.windowTitle())
+        
         if browserFlags & OthersBrowserFlag:
             index = self.addTab(
                 self.poBrowser,
--- a/Project/ProjectBrowserFlags.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Project/ProjectBrowserFlags.py	Sun Nov 12 19:42:02 2017 +0100
@@ -13,12 +13,15 @@
 TranslationsBrowserFlag = 8
 InterfacesBrowserFlag = 16
 OthersBrowserFlag = 32
+ProtocolsBrowserFlag = 64
+
 AllBrowsersFlag = SourcesBrowserFlag | \
     FormsBrowserFlag | \
     ResourcesBrowserFlag | \
     TranslationsBrowserFlag | \
     InterfacesBrowserFlag | \
-    OthersBrowserFlag
+    OthersBrowserFlag | \
+    ProtocolsBrowserFlag
 
 #
 # eflag: noqa = M702
--- a/Project/ProjectBrowserModel.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/Project/ProjectBrowserModel.py	Sun Nov 12 19:42:02 2017 +0100
@@ -35,6 +35,7 @@
 ProjectBrowserTranslationType = 4
 ProjectBrowserOthersType = 5
 ProjectBrowserResourceType = 6
+ProjectBrowserProtocolsType = 7
 
 
 class ProjectBrowserItemMixin(object):
@@ -253,6 +254,7 @@
             "FORMS": ProjectBrowserFormType,
             "RESOURCES": ProjectBrowserResourceType,
             "INTERFACES": ProjectBrowserInterfaceType,
+            "PROTOCOLS": ProjectBrowserProtocolsType,
             "TRANSLATIONS": ProjectBrowserTranslationType,
             "OTHERS": ProjectBrowserOthersType,
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Project/ProjectProtocolsBrowser.py	Sun Nov 12 19:42:02 2017 +0100
@@ -0,0 +1,646 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the a class used to display the protocols (protobuf) part
+of the project.
+"""
+
+from __future__ import unicode_literals
+try:
+    str = unicode
+except NameError:
+    pass
+
+import os
+import glob
+
+from PyQt5.QtCore import QThread, pyqtSignal, QProcess
+from PyQt5.QtWidgets import QDialog, QApplication, QMenu
+
+from E5Gui.E5Application import e5App
+from E5Gui import E5MessageBox
+from E5Gui.E5ProgressDialog import E5ProgressDialog
+
+from .ProjectBrowserModel import ProjectBrowserFileItem, \
+    ProjectBrowserSimpleDirectoryItem, ProjectBrowserDirectoryItem, \
+    ProjectBrowserProtocolsType
+from .ProjectBaseBrowser import ProjectBaseBrowser
+
+from UI.BrowserModel import BrowserFileItem, BrowserClassItem, \
+    BrowserMethodItem, BrowserClassAttributeItem
+import UI.PixmapCache
+
+import Preferences
+import Utilities
+
+
+class ProjectProtocolsBrowser(ProjectBaseBrowser):
+    """
+    A class used to display the protocols (protobuf) part of the project.
+    
+    @signal appendStdout(str) emitted after something was received from
+        a QProcess on stdout
+    @signal appendStderr(str) emitted after something was received from
+        a QProcess on stderr
+    @signal showMenu(str, QMenu) emitted when a menu is about to be shown.
+        The name of the menu and a reference to the menu are given.
+    """
+    appendStdout = pyqtSignal(str)
+    appendStderr = pyqtSignal(str)
+    showMenu = pyqtSignal(str, QMenu)
+    
+    def __init__(self, project, parent=None):
+        """
+        Constructor
+        
+        @param project reference to the project object
+        @type Project
+        @param parent parent widget of this browser
+        @type QWidget
+        """
+        self.__protoc = Preferences.getProtobuf("protoc")
+        if self.__protoc == "":
+            self.__protoc = Utilities.isWindowsPlatform() and \
+                "protoc.exe" or "protoc"
+        if not Utilities.isinpath(self.__protoc):
+            self.__protoc = None
+        self.omniidl = self.__protoc    # TODO: remove this line
+        
+        ProjectBaseBrowser.__init__(self, project,
+                                    ProjectBrowserProtocolsType, parent)
+        
+        self.selectedItemsFilter = \
+            [ProjectBrowserFileItem, ProjectBrowserSimpleDirectoryItem]
+        
+        self.setWindowTitle(self.tr('Protocols (protobuf)'))
+        
+        self.setWhatsThis(self.tr(
+            """<b>Project Protocols Browser</b>"""
+            """<p>This allows to easily see all protocols (protobuf files)"""
+            """ contained in the current project. Several actions can be"""
+            """ executed via the context menu.</p>"""
+        ))
+        
+        project.prepareRepopulateItem.connect(self._prepareRepopulateItem)
+        project.completeRepopulateItem.connect(self._completeRepopulateItem)
+    
+    # TODO: continue from here
+    def _createPopupMenus(self):
+        """
+        Protected overloaded method to generate the popup menu.
+        """
+        self.menuActions = []
+        self.multiMenuActions = []
+        self.dirMenuActions = []
+        self.dirMultiMenuActions = []
+        
+        self.sourceMenu = QMenu(self)
+        if self.omniidl is not None:
+            self.sourceMenu.addAction(
+                self.tr('Compile interface'), self.__compileInterface)
+            self.sourceMenu.addAction(
+                self.tr('Compile all interfaces'),
+                self.__compileAllInterfaces)
+        self.sourceMenu.addAction(self.tr('Open'), self._openItem)
+        self.sourceMenu.addSeparator()
+        act = self.sourceMenu.addAction(
+            self.tr('Rename file'), self._renameFile)
+        self.menuActions.append(act)
+        act = self.sourceMenu.addAction(
+            self.tr('Remove from project'), self._removeFile)
+        self.menuActions.append(act)
+        act = self.sourceMenu.addAction(
+            self.tr('Delete'), self.__deleteFile)
+        self.menuActions.append(act)
+        self.sourceMenu.addSeparator()
+        self.sourceMenu.addAction(
+            self.tr('Add interfaces...'), self.__addInterfaceFiles)
+        self.sourceMenu.addAction(
+            self.tr('Add interfaces directory...'),
+            self.__addInterfacesDirectory)
+        self.sourceMenu.addSeparator()
+        self.sourceMenu.addAction(
+            self.tr('Copy Path to Clipboard'), self._copyToClipboard)
+        self.sourceMenu.addSeparator()
+        self.sourceMenu.addAction(
+            self.tr('Expand all directories'), self._expandAllDirs)
+        self.sourceMenu.addAction(
+            self.tr('Collapse all directories'), self._collapseAllDirs)
+        self.sourceMenu.addSeparator()
+        self.sourceMenu.addAction(self.tr('Configure...'), self._configure)
+        self.sourceMenu.addAction(
+            self.tr('Configure CORBA...'), self.__configureCorba)
+
+        self.menu = QMenu(self)
+        if self.omniidl is not None:
+            self.menu.addAction(
+                self.tr('Compile interface'), self.__compileInterface)
+            self.menu.addAction(
+                self.tr('Compile all interfaces'),
+                self.__compileAllInterfaces)
+        self.menu.addAction(self.tr('Open'), self._openItem)
+        self.menu.addSeparator()
+        self.menu.addAction(
+            self.tr('Add interfaces...'), self.__addInterfaceFiles)
+        self.menu.addAction(
+            self.tr('Add interfaces directory...'),
+            self.__addInterfacesDirectory)
+        self.menu.addSeparator()
+        self.menu.addAction(
+            self.tr('Expand all directories'), self._expandAllDirs)
+        self.menu.addAction(
+            self.tr('Collapse all directories'), self._collapseAllDirs)
+        self.menu.addSeparator()
+        self.menu.addAction(self.tr('Configure...'), self._configure)
+        self.menu.addAction(
+            self.tr('Configure CORBA...'), self.__configureCorba)
+
+        self.backMenu = QMenu(self)
+        if self.omniidl is not None:
+            self.backMenu.addAction(
+                self.tr('Compile all interfaces'),
+                self.__compileAllInterfaces)
+            self.backMenu.addSeparator()
+        self.backMenu.addAction(
+            self.tr('Add interfaces...'), self.project.addIdlFiles)
+        self.backMenu.addAction(
+            self.tr('Add interfaces directory...'), self.project.addIdlDir)
+        self.backMenu.addSeparator()
+        self.backMenu.addAction(
+            self.tr('Expand all directories'), self._expandAllDirs)
+        self.backMenu.addAction(
+            self.tr('Collapse all directories'), self._collapseAllDirs)
+        self.backMenu.addSeparator()
+        self.backMenu.addAction(self.tr('Configure...'), self._configure)
+        self.backMenu.addAction(
+            self.tr('Configure CORBA...'), self.__configureCorba)
+        self.backMenu.setEnabled(False)
+
+        # create the menu for multiple selected files
+        self.multiMenu = QMenu(self)
+        if self.omniidl is not None:
+            self.multiMenu.addAction(
+                self.tr('Compile interfaces'),
+                self.__compileSelectedInterfaces)
+        self.multiMenu.addAction(self.tr('Open'), self._openItem)
+        self.multiMenu.addSeparator()
+        act = self.multiMenu.addAction(
+            self.tr('Remove from project'), self._removeFile)
+        self.multiMenuActions.append(act)
+        act = self.multiMenu.addAction(
+            self.tr('Delete'), self.__deleteFile)
+        self.multiMenuActions.append(act)
+        self.multiMenu.addSeparator()
+        self.multiMenu.addAction(
+            self.tr('Expand all directories'), self._expandAllDirs)
+        self.multiMenu.addAction(
+            self.tr('Collapse all directories'), self._collapseAllDirs)
+        self.multiMenu.addSeparator()
+        self.multiMenu.addAction(self.tr('Configure...'), self._configure)
+        self.multiMenu.addAction(
+            self.tr('Configure CORBA...'), self.__configureCorba)
+
+        self.dirMenu = QMenu(self)
+        if self.omniidl is not None:
+            self.dirMenu.addAction(
+                self.tr('Compile all interfaces'),
+                self.__compileAllInterfaces)
+            self.dirMenu.addSeparator()
+        act = self.dirMenu.addAction(
+            self.tr('Remove from project'), self._removeFile)
+        self.dirMenuActions.append(act)
+        act = self.dirMenu.addAction(
+            self.tr('Delete'), self._deleteDirectory)
+        self.dirMenuActions.append(act)
+        self.dirMenu.addSeparator()
+        self.dirMenu.addAction(
+            self.tr('Add interfaces...'), self.__addInterfaceFiles)
+        self.dirMenu.addAction(
+            self.tr('Add interfaces directory...'),
+            self.__addInterfacesDirectory)
+        self.dirMenu.addSeparator()
+        self.dirMenu.addAction(
+            self.tr('Copy Path to Clipboard'), self._copyToClipboard)
+        self.dirMenu.addSeparator()
+        self.dirMenu.addAction(
+            self.tr('Expand all directories'), self._expandAllDirs)
+        self.dirMenu.addAction(
+            self.tr('Collapse all directories'), self._collapseAllDirs)
+        self.dirMenu.addSeparator()
+        self.dirMenu.addAction(self.tr('Configure...'), self._configure)
+        self.dirMenu.addAction(
+            self.tr('Configure CORBA...'), self.__configureCorba)
+        
+        self.dirMultiMenu = QMenu(self)
+        if self.omniidl is not None:
+            self.dirMultiMenu.addAction(
+                self.tr('Compile all interfaces'),
+                self.__compileAllInterfaces)
+            self.dirMultiMenu.addSeparator()
+        self.dirMultiMenu.addAction(
+            self.tr('Add interfaces...'), self.project.addIdlFiles)
+        self.dirMultiMenu.addAction(
+            self.tr('Add interfaces directory...'), self.project.addIdlDir)
+        self.dirMultiMenu.addSeparator()
+        self.dirMultiMenu.addAction(
+            self.tr('Expand all directories'), self._expandAllDirs)
+        self.dirMultiMenu.addAction(
+            self.tr('Collapse all directories'), self._collapseAllDirs)
+        self.dirMultiMenu.addSeparator()
+        self.dirMultiMenu.addAction(
+            self.tr('Configure...'), self._configure)
+        self.dirMultiMenu.addAction(self.tr('Configure CORBA...'),
+                                    self.__configureCorba)
+        
+        self.sourceMenu.aboutToShow.connect(self.__showContextMenu)
+        self.multiMenu.aboutToShow.connect(self.__showContextMenuMulti)
+        self.dirMenu.aboutToShow.connect(self.__showContextMenuDir)
+        self.dirMultiMenu.aboutToShow.connect(self.__showContextMenuDirMulti)
+        self.backMenu.aboutToShow.connect(self.__showContextMenuBack)
+        self.mainMenu = self.sourceMenu
+        
+    def _contextMenuRequested(self, coord):
+        """
+        Protected slot to show the context menu.
+        
+        @param coord the position of the mouse pointer (QPoint)
+        """
+        if not self.project.isOpen():
+            return
+        
+        try:
+            categories = self.getSelectedItemsCountCategorized(
+                [ProjectBrowserFileItem, BrowserClassItem,
+                 BrowserMethodItem, ProjectBrowserSimpleDirectoryItem])
+            cnt = categories["sum"]
+            if cnt <= 1:
+                index = self.indexAt(coord)
+                if index.isValid():
+                    self._selectSingleItem(index)
+                    categories = self.getSelectedItemsCountCategorized(
+                        [ProjectBrowserFileItem, BrowserClassItem,
+                         BrowserMethodItem, ProjectBrowserSimpleDirectoryItem])
+                    cnt = categories["sum"]
+            
+            bfcnt = categories[str(ProjectBrowserFileItem)]
+            cmcnt = categories[str(BrowserClassItem)] + \
+                categories[str(BrowserMethodItem)]
+            sdcnt = categories[str(ProjectBrowserSimpleDirectoryItem)]
+            if cnt > 1 and cnt == bfcnt:
+                self.multiMenu.popup(self.mapToGlobal(coord))
+            elif cnt > 1 and cnt == sdcnt:
+                self.dirMultiMenu.popup(self.mapToGlobal(coord))
+            else:
+                index = self.indexAt(coord)
+                if cnt == 1 and index.isValid():
+                    if bfcnt == 1 or cmcnt == 1:
+                        itm = self.model().item(index)
+                        if isinstance(itm, ProjectBrowserFileItem):
+                            self.sourceMenu.popup(self.mapToGlobal(coord))
+                        elif isinstance(itm, BrowserClassItem) or \
+                                isinstance(itm, BrowserMethodItem):
+                            self.menu.popup(self.mapToGlobal(coord))
+                        else:
+                            self.backMenu.popup(self.mapToGlobal(coord))
+                    elif sdcnt == 1:
+                        self.dirMenu.popup(self.mapToGlobal(coord))
+                    else:
+                        self.backMenu.popup(self.mapToGlobal(coord))
+                else:
+                    self.backMenu.popup(self.mapToGlobal(coord))
+        except Exception:
+            pass
+        
+    def __showContextMenu(self):
+        """
+        Private slot called by the menu aboutToShow signal.
+        """
+        ProjectBaseBrowser._showContextMenu(self, self.menu)
+        
+        self.showMenu.emit("Main", self.menu)
+        
+    def __showContextMenuMulti(self):
+        """
+        Private slot called by the multiMenu aboutToShow signal.
+        """
+        ProjectBaseBrowser._showContextMenuMulti(self, self.multiMenu)
+        
+        self.showMenu.emit("MainMulti", self.multiMenu)
+        
+    def __showContextMenuDir(self):
+        """
+        Private slot called by the dirMenu aboutToShow signal.
+        """
+        ProjectBaseBrowser._showContextMenuDir(self, self.dirMenu)
+        
+        self.showMenu.emit("MainDir", self.dirMenu)
+        
+    def __showContextMenuDirMulti(self):
+        """
+        Private slot called by the dirMultiMenu aboutToShow signal.
+        """
+        ProjectBaseBrowser._showContextMenuDirMulti(self, self.dirMultiMenu)
+        
+        self.showMenu.emit("MainDirMulti", self.dirMultiMenu)
+        
+    def __showContextMenuBack(self):
+        """
+        Private slot called by the backMenu aboutToShow signal.
+        """
+        ProjectBaseBrowser._showContextMenuBack(self, self.backMenu)
+        
+        self.showMenu.emit("MainBack", self.backMenu)
+        
+    def _openItem(self):
+        """
+        Protected slot to handle the open popup menu entry.
+        """
+        itmList = self.getSelectedItems(
+            [BrowserFileItem, BrowserClassItem, BrowserMethodItem,
+             BrowserClassAttributeItem])
+        
+        for itm in itmList:
+            if isinstance(itm, BrowserFileItem):
+                self.sourceFile[str].emit(itm.fileName())
+            elif isinstance(itm, BrowserClassItem):
+                self.sourceFile[str, int].emit(
+                    itm.fileName(), itm.classObject().lineno)
+            elif isinstance(itm, BrowserMethodItem):
+                self.sourceFile[str, int].emit(
+                    itm.fileName(), itm.functionObject().lineno)
+            elif isinstance(itm, BrowserClassAttributeItem):
+                self.sourceFile[str, int].emit(
+                    itm.fileName(), itm.attributeObject().lineno)
+        
+    def __addInterfaceFiles(self):
+        """
+        Private method to add interface files to the project.
+        """
+        itm = self.model().item(self.currentIndex())
+        if isinstance(itm, ProjectBrowserFileItem) or \
+           isinstance(itm, BrowserClassItem) or \
+           isinstance(itm, BrowserMethodItem):
+            dn = os.path.dirname(itm.fileName())
+        elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
+                isinstance(itm, ProjectBrowserDirectoryItem):
+            dn = itm.dirName()
+        else:
+            dn = None
+        self.project.addFiles('interface', dn)
+        
+    def __addInterfacesDirectory(self):
+        """
+        Private method to add interface files of a directory to the project.
+        """
+        itm = self.model().item(self.currentIndex())
+        if isinstance(itm, ProjectBrowserFileItem) or \
+           isinstance(itm, BrowserClassItem) or \
+           isinstance(itm, BrowserMethodItem):
+            dn = os.path.dirname(itm.fileName())
+        elif isinstance(itm, ProjectBrowserSimpleDirectoryItem) or \
+                isinstance(itm, ProjectBrowserDirectoryItem):
+            dn = itm.dirName()
+        else:
+            dn = None
+        self.project.addDirectory('interface', dn)
+        
+    def __deleteFile(self):
+        """
+        Private method to delete files from the project.
+        """
+        itmList = self.getSelectedItems()
+        
+        files = []
+        fullNames = []
+        for itm in itmList:
+            fn2 = itm.fileName()
+            fullNames.append(fn2)
+            fn = self.project.getRelativePath(fn2)
+            files.append(fn)
+        
+        from UI.DeleteFilesConfirmationDialog import \
+            DeleteFilesConfirmationDialog
+        dlg = DeleteFilesConfirmationDialog(
+            self.parent(),
+            self.tr("Delete interfaces"),
+            self.tr("Do you really want to delete these interfaces from"
+                    " the project?"),
+            files)
+        
+        if dlg.exec_() == QDialog.Accepted:
+            for fn2, fn in zip(fullNames, files):
+                self.closeSourceWindow.emit(fn2)
+                self.project.deleteFile(fn)
+    
+    ###########################################################################
+    ##  Methods to handle the various compile commands
+    ###########################################################################
+    
+    def __readStdout(self):
+        """
+        Private slot to handle the readyReadStandardOutput signal of the
+        omniidl process.
+        """
+        if self.compileProc is None:
+            return
+        
+        ioEncoding = Preferences.getSystem("IOEncoding")
+        
+        self.compileProc.setReadChannel(QProcess.StandardOutput)
+        while self.compileProc and self.compileProc.canReadLine():
+            s = 'omniidl: '
+            output = str(self.compileProc.readLine(), ioEncoding, 'replace')
+            s += output
+            self.appendStdout.emit(s)
+        
+    def __readStderr(self):
+        """
+        Private slot to handle the readyReadStandardError signal of the
+        omniidl process.
+        """
+        if self.compileProc is None:
+            return
+        
+        ioEncoding = Preferences.getSystem("IOEncoding")
+        
+        self.compileProc.setReadChannel(QProcess.StandardError)
+        while self.compileProc and self.compileProc.canReadLine():
+            s = 'omniidl: '
+            error = str(self.compileProc.readLine(), ioEncoding, 'replace')
+            s += error
+            self.appendStderr.emit(s)
+        
+    def __compileIDLDone(self, exitCode, exitStatus):
+        """
+        Private slot to handle the finished signal of the omniidl process.
+        
+        @param exitCode exit code of the process (integer)
+        @param exitStatus exit status of the process (QProcess.ExitStatus)
+        """
+        self.compileRunning = False
+        ui = e5App().getObject("UserInterface")
+        if exitStatus == QProcess.NormalExit and exitCode == 0:
+            path = os.path.dirname(self.idlFile)
+            poaList = glob.glob(os.path.join(path, "*__POA"))
+            npoaList = [f.replace("__POA", "") for f in poaList]
+            fileList = glob.glob(os.path.join(path, "*_idl.py"))
+            for directory in poaList + npoaList:
+                fileList += Utilities.direntries(directory, True, "*.py")
+            for file in fileList:
+                self.project.appendFile(file)
+            if not self.noDialog and not ui.notificationsEnabled():
+                E5MessageBox.information(
+                    self,
+                    self.tr("Interface Compilation"),
+                    self.tr(
+                        "The compilation of the interface file was"
+                        " successful."))
+            else:
+                ui.showNotification(
+                    UI.PixmapCache.getPixmap("corba48.png"),
+                    self.tr("Interface Compilation"),
+                    self.tr(
+                        "The compilation of the interface file was"
+                        " successful."))
+        else:
+            if not self.noDialog:
+                E5MessageBox.information(
+                    self,
+                    self.tr("Interface Compilation"),
+                    self.tr(
+                        "The compilation of the interface file failed."))
+            else:
+                ui.showNotification(
+                    UI.PixmapCache.getPixmap("corba48.png"),
+                    self.tr("Interface Compilation"),
+                    self.tr(
+                        "The compilation of the interface file failed."))
+        self.compileProc = None
+        
+    def __compileIDL(self, fn, noDialog=False, progress=None):
+        """
+        Private method to compile a .idl file to python.
+
+        @param fn filename of the .idl file to be compiled (string)
+        @param noDialog flag indicating silent operations (boolean)
+        @param progress reference to the progress dialog (E5ProgressDialog)
+        @return reference to the compile process (QProcess)
+        """
+        self.compileProc = QProcess()
+        args = []
+        
+        args.append("-bpython")
+        args.append("-I.")
+        
+        fn = os.path.join(self.project.ppath, fn)
+        self.idlFile = fn
+        args.append("-C{0}".format(os.path.dirname(fn)))
+        args.append(fn)
+        
+        self.compileProc.finished.connect(self.__compileIDLDone)
+        self.compileProc.readyReadStandardOutput.connect(self.__readStdout)
+        self.compileProc.readyReadStandardError.connect(self.__readStderr)
+        
+        self.noDialog = noDialog
+        self.compileProc.start(self.omniidl, args)
+        procStarted = self.compileProc.waitForStarted(5000)
+        if procStarted:
+            self.compileRunning = True
+            return self.compileProc
+        else:
+            self.compileRunning = False
+            if progress is not None:
+                progress.cancel()
+            E5MessageBox.critical(
+                self,
+                self.tr('Process Generation Error'),
+                self.tr(
+                    '<p>Could not start {0}.<br>'
+                    'Ensure that it is in the search path.</p>'
+                ).format(self.omniidl))
+            return None
+        
+    def __compileInterface(self):
+        """
+        Private method to compile an interface to python.
+        """
+        if self.omniidl is not None:
+            itm = self.model().item(self.currentIndex())
+            fn2 = itm.fileName()
+            fn = self.project.getRelativePath(fn2)
+            self.__compileIDL(fn)
+        
+    def __compileAllInterfaces(self):
+        """
+        Private method to compile all interfaces to python.
+        """
+        if self.omniidl is not None:
+            numIDLs = len(self.project.pdata["INTERFACES"])
+            progress = E5ProgressDialog(
+                self.tr("Compiling interfaces..."),
+                self.tr("Abort"), 0, numIDLs,
+                self.tr("%v/%m Interfaces"), self)
+            progress.setModal(True)
+            progress.setMinimumDuration(0)
+            progress.setWindowTitle(self.tr("Interfaces"))
+            i = 0
+            
+            for fn in self.project.pdata["INTERFACES"]:
+                progress.setValue(i)
+                if progress.wasCanceled():
+                    break
+                proc = self.__compileIDL(fn, True, progress)
+                if proc is not None:
+                    while proc.state() == QProcess.Running:
+                        QApplication.processEvents()
+                        QThread.msleep(300)
+                        QApplication.processEvents()
+                else:
+                    break
+                i += 1
+            
+            progress.setValue(numIDLs)
+        
+    def __compileSelectedInterfaces(self):
+        """
+        Private method to compile selected interfaces to python.
+        """
+        if self.omniidl is not None:
+            items = self.getSelectedItems()
+            
+            files = [self.project.getRelativePath(itm.fileName())
+                     for itm in items]
+            numIDLs = len(files)
+            progress = E5ProgressDialog(
+                self.tr("Compiling interfaces..."),
+                self.tr("Abort"), 0, numIDLs,
+                self.tr("%v/%m Interfaces"), self)
+            progress.setModal(True)
+            progress.setMinimumDuration(0)
+            progress.setWindowTitle(self.tr("Interfaces"))
+            i = 0
+            
+            for fn in files:
+                progress.setValue(i)
+                if progress.wasCanceled():
+                    break
+                proc = self.__compileIDL(fn, True, progress)
+                if proc is not None:
+                    while proc.state() == QProcess.Running:
+                        QApplication.processEvents()
+                        QThread.msleep(300)
+                        QApplication.processEvents()
+                else:
+                    break
+                i += 1
+                
+            progress.setValue(numIDLs)
+        
+    def __configureCorba(self):
+        """
+        Private method to open the configuration dialog.
+        """
+        e5App().getObject("UserInterface").showPreferences("corbaPage")
--- a/UI/Browser.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/UI/Browser.py	Sun Nov 12 19:42:02 2017 +0100
@@ -463,6 +463,8 @@
                         self.multiProjectFile.emit(itm.fileName())
                     elif itm.isIdlFile():
                         self.sourceFile[str].emit(itm.fileName())
+                    elif itm.isProtobufFile():
+                        self.sourceFile[str].emit(itm.fileName())
                     elif itm.isResourcesFile():
                         self.sourceFile[str].emit(itm.fileName())
                     elif itm.isSvgFile():
--- a/UI/BrowserModel.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/UI/BrowserModel.py	Sun Nov 12 19:42:02 2017 +0100
@@ -1135,6 +1135,8 @@
             self._populated = False
             self._lazyPopulation = True
             self._moduleName = os.path.basename(finfo)
+        elif self.isProtobufFile():
+            pixName = "protobuf.png"
         elif self.isSvgFile():
             pixName = "fileSvg.png"
         elif self.isPixmapFile():
@@ -1285,6 +1287,15 @@
         """
         return self.fileext == '.idl'
     
+    def isProtobufFile(self):
+        """
+        Public method to check, if this file is a Google Protocol Buffer file.
+        
+        @return flag indicating a protobuf file
+        @rtype bool
+        """
+        return self.fileext == ".proto"
+    
     def isJavaScriptFile(self):
         """
         Public method to check, if this file is a JavaScript file.
--- a/UI/UserInterface.py	Sat Nov 11 18:47:09 2017 +0100
+++ b/UI/UserInterface.py	Sun Nov 12 19:42:02 2017 +0100
@@ -357,6 +357,15 @@
         self.projectBrowser.piBrowser.appendStdout.connect(self.appendToStdout)
         self.projectBrowser.piBrowser.appendStderr.connect(self.appendToStderr)
         
+        self.projectBrowser.ppBrowser.sourceFile[str].connect(
+            self.viewmanager.openSourceFile)
+        self.projectBrowser.ppBrowser.sourceFile[str, int].connect(
+            self.viewmanager.openSourceFile)
+        self.projectBrowser.ppBrowser.closeSourceWindow.connect(
+            self.viewmanager.closeWindow)
+        self.projectBrowser.ppBrowser.appendStdout.connect(self.appendToStdout)
+        self.projectBrowser.ppBrowser.appendStderr.connect(self.appendToStderr)
+        
         self.projectBrowser.poBrowser.sourceFile.connect(
             self.viewmanager.openSourceFile)
         self.projectBrowser.poBrowser.closeSourceWindow.connect(
@@ -445,6 +454,8 @@
         self.preferencesChanged.connect(
             self.projectBrowser.piBrowser.handlePreferencesChanged)
         self.preferencesChanged.connect(
+            self.projectBrowser.ppBrowser.handlePreferencesChanged)
+        self.preferencesChanged.connect(
             self.projectBrowser.poBrowser.handlePreferencesChanged)
         self.preferencesChanged.connect(self.browser.handlePreferencesChanged)
         self.preferencesChanged.connect(
--- a/eric6.e4p	Sat Nov 11 18:47:09 2017 +0100
+++ b/eric6.e4p	Sun Nov 12 19:42:02 2017 +0100
@@ -783,6 +783,7 @@
     <Source>Preferences/ConfigurationPages/PrinterPage.py</Source>
     <Source>Preferences/ConfigurationPages/ProjectBrowserPage.py</Source>
     <Source>Preferences/ConfigurationPages/ProjectPage.py</Source>
+    <Source>Preferences/ConfigurationPages/ProtobufPage.py</Source>
     <Source>Preferences/ConfigurationPages/PythonPage.py</Source>
     <Source>Preferences/ConfigurationPages/QtPage.py</Source>
     <Source>Preferences/ConfigurationPages/SecurityPage.py</Source>
@@ -825,6 +826,7 @@
     <Source>Project/ProjectFormsBrowser.py</Source>
     <Source>Project/ProjectInterfacesBrowser.py</Source>
     <Source>Project/ProjectOthersBrowser.py</Source>
+    <Source>Project/ProjectProtocolsBrowser.py</Source>
     <Source>Project/ProjectResourcesBrowser.py</Source>
     <Source>Project/ProjectSourcesBrowser.py</Source>
     <Source>Project/ProjectTranslationsBrowser.py</Source>
@@ -1849,6 +1851,7 @@
     <Form>Preferences/ConfigurationPages/PrinterPage.ui</Form>
     <Form>Preferences/ConfigurationPages/ProjectBrowserPage.ui</Form>
     <Form>Preferences/ConfigurationPages/ProjectPage.ui</Form>
+    <Form>Preferences/ConfigurationPages/ProtobufPage.ui</Form>
     <Form>Preferences/ConfigurationPages/PythonPage.ui</Form>
     <Form>Preferences/ConfigurationPages/QtPage.ui</Form>
     <Form>Preferences/ConfigurationPages/SecurityPage.ui</Form>
Binary file icons/default/protobuf.png has changed

eric ide

mercurial