About, early release and news dialogs.

Client notification.
This commit is contained in:
grossmj
2014-03-19 18:24:07 -06:00
parent 50b06d815a
commit 0ccf8b9e7c
23 changed files with 7115 additions and 14 deletions

36
gns3/about_dialog.py Normal file
View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
from .qt import QtGui
from .version import __version__
from .ui.about_dialog_ui import Ui_AboutDialog
class AboutDialog(QtGui.QDialog, Ui_AboutDialog):
"""
About dialog.
"""
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
# dynamically add the current version number
text = self.uiAboutTextLabel.text()
text = text.replace("%VERSION%", __version__)
self.uiAboutTextLabel.setText(text)

View File

@@ -20,6 +20,7 @@ import sys
from .version import __version__
from .console_cmd import ConsoleCmd
from .pycutext import PyCutExt
from .modules import MODULES
class ConsoleView(PyCutExt, ConsoleCmd):
@@ -69,6 +70,10 @@ class ConsoleView(PyCutExt, ConsoleCmd):
except Exception as e:
sys.stderr.write(e)
for module in MODULES:
instance = module.instance()
instance.notification_signal.connect(self.writeNotification)
def onKeyPress_Tab(self):
"""
Imitate cmd.Cmd.complete(self, text, state) function.
@@ -116,6 +121,20 @@ class ConsoleView(PyCutExt, ConsoleCmd):
# In any case, reprint prompt + line
self.write("\n" + sys.ps1 + str(self.line))
def writeNotification(self, message, details):
"""
Write notification messages coming from the server.
:param message: notification message
:param details: details (text)
"""
text = "Server notification: {}".format(message)
self.write(text, error=True)
self.write("\n")
self.write(details)
self.write("\n")
def writeError(self, name, code, message):
"""
Write error messages coming from the server.

View File

@@ -0,0 +1,61 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
import re
from .qt import QtGui
from .ui.early_release_dialog_ui import Ui_EarlyReleaseDialog
class EarlyReleaseDialog(QtGui.QDialog, Ui_EarlyReleaseDialog):
"""
Early release dialog.
"""
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
def isEmail(self, email):
if re.match("[\.\w]{1,}[@]\w+[.]\w+", email):
return True
else:
return False
def done(self, result):
if not result: # cancelled
QtGui.QApplication.quit()
else:
username = self.uiUsernameLineEdit.text()
if not username:
QtGui.QMessageBox.critical(self, "Username", "Please provide an username")
return
email = self.uiEmailLineEdit.text()
if not email:
QtGui.QMessageBox.critical(self, "Email", "Please provide an email address")
return
if not re.search(r"""^GNS[34]{1}[0-9]{4}$""", username) or not self.isEmail(email):
QtGui.QMessageBox.critical(self, "Invalid membership", "Sorry this is an invalid membership")
return
if not self.uiDisclaimerCheckBox.isChecked():
QtGui.QMessageBox.critical(self, "Disclaimer", "Please read the disclaimer!")
return
# Congratulations, you found where we check for a GNS3 membership! and yes, it is very simple ;)
# Since you were smart enough to get here, you deserve to use GNS3 without a membership...
QtGui.QDialog.done(self, result)

View File

@@ -28,6 +28,9 @@ from .qt import QtGui, QtCore
from .servers import Servers
from .node import Node
from .ui.main_window_ui import Ui_MainWindow
from .about_dialog import AboutDialog
from .news_dialog import NewsDialog
from .early_release_dialog import EarlyReleaseDialog
from .preferences_dialog import PreferencesDialog
from .settings import GENERAL_SETTINGS, GENERAL_SETTING_TYPES
from .utils.progress_dialog import ProgressDialog
@@ -36,6 +39,8 @@ from .utils.wait_for_connection_thread import WaitForConnectionThread
from .utils.message_box import MessageBox
from .items.node_item import NodeItem
from .topology import Topology
from .version import __version__
import logging
log = logging.getLogger(__name__)
@@ -508,8 +513,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Slot to open the news dialog.
"""
#TODO: news dialog implementation
QtGui.QMessageBox.critical(self, "News", "Sorry, to be implemented!")
try:
# QtWebKit is not installed by default on FreeBSD, Solaris and possibly other systems.
from .qt import QtWebKit
except ImportError:
return
dialog = NewsDialog(self)
dialog.show()
dialog.exec_()
def _labInstructionsActionSlot(self):
"""
@@ -531,8 +543,9 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
Slot to display the GNS3 About dialog.
"""
#TODO: about dialog.
QtGui.QMessageBox.critical(self, "About", "Sorry, to be implemented!")
dialog = AboutDialog(self)
dialog.show()
dialog.exec_()
# def _doSlidingWindow(self, type):
# """
@@ -724,6 +737,15 @@ class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
port=server.port,
error=e))
config_filename = QtCore.QSettings().fileName()
if not os.access(config_filename, os.F_OK):
# no config file detected, first time we start this application
dialog = EarlyReleaseDialog(self)
dialog.show()
dialog.exec_()
self._newsActionSlot()
def _saveProjectAs(self):
"""
Saves a project to another location/name.

View File

@@ -55,6 +55,7 @@ class Dynamips(Module):
self._settings = {}
self._ios_images = {}
self._servers = []
self._nodes = []
self._working_dir = ""
# load the settings and IOS images.
@@ -193,6 +194,24 @@ class Dynamips(Module):
return self._servers
def addNode(self, node):
"""
Adds a node to this module.
:param node: Node instance
"""
self._nodes.append(node)
def removeNode(self, node):
"""
Removes a node from this module.
:param node: Node instance
"""
self._nodes.remove(node)
def iosImages(self):
"""
Returns IOS images settings.
@@ -355,6 +374,21 @@ class Dynamips(Module):
if server.connected():
server.send_notification("dynamips.reset")
def notification(self, destination, params):
"""
To received notifications from the server.
:param destination: JSON-RPC method
:param params: JSON-RPC params
"""
if "id" in params and "name" in params:
for node in self._nodes:
if node.id() == params["id"] and node.name() == params["name"]:
message = "node {}: {}".format(node.name(), params["message"])
self.notification_signal.emit(message, params["details"])
node.stop()
@staticmethod
def getNodeClass(name):
"""

View File

@@ -80,6 +80,7 @@ class ATMSwitch(Node):
log.info("ATM switch {} has been created".format(self.name()))
self.setInitialized(True)
self.created_signal.emit(self.id())
self._module.addNode(self)
def delete(self):
"""
@@ -93,6 +94,7 @@ class ATMSwitch(Node):
self._server.send_message("dynamips.atmsw.delete", {"id": self._atmsw_id}, self._deleteCallback)
else:
self.delete_signal.emit()
self._module.removeNode(self)
def _deleteCallback(self, result, error=False):
"""
@@ -107,6 +109,7 @@ class ATMSwitch(Node):
self.error_signal.emit(self.name(), result["code"], result["message"])
log.info("ATM switch {} has been deleted".format(self.name()))
self.delete_signal.emit()
self._module.removeNode(self)
def update(self, new_settings):
"""

View File

@@ -78,6 +78,7 @@ class EthernetHub(Node):
log.info("Ethernet hub {} has been created".format(self.name()))
self.setInitialized(True)
self.created_signal.emit(self.id())
self._module.addNode(self)
def delete(self):
"""
@@ -91,6 +92,7 @@ class EthernetHub(Node):
self._server.send_message("dynamips.ethhub.delete", {"id": self._ethhub_id}, self._deleteCallback)
else:
self.delete_signal.emit()
self._module.removeNode(self)
def _deleteCallback(self, result, error=False):
"""
@@ -105,6 +107,7 @@ class EthernetHub(Node):
self.error_signal.emit(self.name(), result["code"], result["message"])
log.info("{} has been deleted".format(self.name()))
self.delete_signal.emit()
self._module.removeNode(self)
def update(self, new_settings):
"""

View File

@@ -78,6 +78,7 @@ class EthernetSwitch(Node):
log.info("Ethernet switch {} has been created".format(self.name()))
self.setInitialized(True)
self.created_signal.emit(self.id())
self._module.addNode(self)
def delete(self):
"""
@@ -91,6 +92,7 @@ class EthernetSwitch(Node):
self._server.send_message("dynamips.ethsw.delete", {"id": self._ethsw_id}, self._deleteCallback)
else:
self.delete_signal.emit()
self._module.removeNode(self)
def _deleteCallback(self, result, error=False):
"""
@@ -105,6 +107,7 @@ class EthernetSwitch(Node):
self.error_signal.emit(self.name(), result["code"], result["message"])
log.info("Ethernet switch {} has been deleted".format(self.name()))
self.delete_signal.emit()
self._module.removeNode(self)
def update(self, new_settings):
"""

View File

@@ -80,6 +80,7 @@ class FrameRelaySwitch(Node):
log.info("Frame Relay switch {} has been created".format(self.name()))
self.setInitialized(True)
self.created_signal.emit(self.id())
self._module.addNode(self)
def delete(self):
"""
@@ -93,6 +94,7 @@ class FrameRelaySwitch(Node):
self._server.send_message("dynamips.frsw.delete", {"id": self._frsw_id}, self._deleteCallback)
else:
self.delete_signal.emit()
self._module.removeNode(self)
def _deleteCallback(self, result, error=False):
"""
@@ -107,6 +109,7 @@ class FrameRelaySwitch(Node):
self.error_signal.emit(self.name(), result["code"], result["message"])
log.info("{} has been deleted".format(self.name()))
self.delete_signal.emit()
self._module.removeNode(self)
def update(self, new_settings):
"""

View File

@@ -201,6 +201,7 @@ class Router(Node):
self._server.send_message("dynamips.vm.delete", {"id": self._router_id}, self._deleteCallback)
else:
self.delete_signal.emit()
self._module.removeNode(self)
def _deleteCallback(self, result, error=False):
"""
@@ -215,6 +216,7 @@ class Router(Node):
self.error_signal.emit(self.name(), result["code"], result["message"])
log.info("router {} has been deleted".format(self.name()))
self.delete_signal.emit()
self._module.removeNode(self)
def setup(self, image, ram, name=None, initial_settings={}):
"""
@@ -292,6 +294,7 @@ class Router(Node):
self.setInitialized(True)
log.debug("router {} has been created".format(self.name()))
self.created_signal.emit(self.id())
self._module.addNode(self)
def _base64Config(self, config_path):
"""
@@ -383,6 +386,7 @@ class Router(Node):
self.setInitialized(True)
log.info("router {} has been created".format(self.name()))
self.created_signal.emit(self.id())
self._module.addNode(self)
self._inital_settings = None
elif updated:
log.info("router {} has been updated".format(self.name()))
@@ -844,6 +848,7 @@ class Router(Node):
self.setInitialized(True)
log.info("router {} has been loaded".format(self.name()))
self.created_signal.emit(self.id())
self._module.addNode(self)
self._inital_settings = None
self._loading = False

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file '/home/grossmj/workspace/git/gns3-gui/gns3/modules/dynamips/ui/router_configuration_page.ui'
#
# Created: Tue Mar 18 17:23:00 2014
# Created: Wed Mar 19 13:25:01 2014
# by: PyQt4 UI code generator 4.10
#
# WARNING! All changes made in this file will be lost!

View File

@@ -42,6 +42,7 @@ class IOU(Module):
Module.__init__(self)
self._settings = {}
self._nodes = []
self._iou_images = {}
self._servers = []
self._working_dir = ""
@@ -176,6 +177,24 @@ class IOU(Module):
return self._servers
def addNode(self, node):
"""
Adds a node to this module.
:param node: Node instance
"""
self._nodes.append(node)
def removeNode(self, node):
"""
Removes a node from this module.
:param node: Node instance
"""
self._nodes.remove(node)
def iouImages(self):
"""
Returns IOU images settings.
@@ -333,6 +352,21 @@ class IOU(Module):
if server.connected():
server.send_notification("iou.reset")
def notification(self, destination, params):
"""
To received notifications from the server.
:param destination: JSON-RPC method
:param params: JSON-RPC params
"""
if "id" in params:
for node in self._nodes:
if node.id() == params["id"]:
message = "node {}: {}".format(node.name(), params["message"])
self.notification_signal.emit(message, params["details"])
node.stop()
@staticmethod
def getNodeClass(name):
"""

View File

@@ -149,6 +149,7 @@ class IOUDevice(Node):
self.setInitialized(True)
log.info("IOU instance {} has been created".format(self.name()))
self.created_signal.emit(self.id())
self._module.addNode(self)
def delete(self):
"""
@@ -162,6 +163,7 @@ class IOUDevice(Node):
self._server.send_message("iou.delete", {"id": self._iou_id}, self._deleteCallback)
else:
self.delete_signal.emit()
self._module.removeNode(self)
def _deleteCallback(self, result, error=False):
"""
@@ -174,9 +176,9 @@ class IOUDevice(Node):
if error:
log.error("error while deleting {}: {}".format(self.name(), result["message"]))
self.error_signal.emit(self.name(), result["code"], result["message"])
else:
log.info("{} has been deleted".format(self.name()))
self.delete_signal.emit()
log.info("{} has been deleted".format(self.name()))
self.delete_signal.emit()
self._module.removeNode(self)
def _base64Config(self, config_path):
"""
@@ -250,6 +252,7 @@ class IOUDevice(Node):
self.setInitialized(True)
log.info("IOU device {} has been created".format(self.name()))
self.created_signal.emit(self.id())
self._module.addNode(self)
self._inital_settings = None
elif updated:
log.info("IOU device {} has been updated".format(self.name()))
@@ -496,6 +499,7 @@ class IOUDevice(Node):
self.setInitialized(True)
log.info("router {} has been loaded".format(self.name()))
self.created_signal.emit(self.id())
self._module.addNode(self)
self._inital_settings = None
self._loading = False

View File

@@ -19,18 +19,22 @@
Base class (interface) for modules.
"""
from ..qt import QtCore
import logging
log = logging.getLogger(__name__)
class Module(object):
class Module(QtCore.QObject):
"""
Module interface.
"""
notification_signal = QtCore.Signal(str, str)
def __init__(self):
pass
super(Module, self).__init__()
@staticmethod
def nodes(self):
@@ -53,3 +57,14 @@ class Module(object):
"""
raise NotImplementedError()
def notification(self, destination, params):
"""
To received notifications from the server.
Must be overloaded.
:param destination: JSON-RPC method
:param params: JSON-RPC params
"""
raise NotImplementedError()

74
gns3/news_dialog.py Normal file
View File

@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
from .qt import QtCore, QtGui
# QtWebKit is not installed by default on FreeBSD, Solaris and possibly other systems.
try:
from .ui.news_dialog_ui import Ui_NewsDialog
from .qt import QtWebKit
except ImportError:
pass
class NewsDialog(QtGui.QDialog, Ui_NewsDialog):
"""
News dialog.
"""
def __init__(self, parent):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.webpage = QtCore.QUrl('http://ads.gns3.net/ads.php')
self.uiWebView.page().setLinkDelegationPolicy(QtWebKit.QWebPage.DelegateAllLinks)
self.connect(self.uiWebView, QtCore.SIGNAL('linkClicked(const QUrl &)'), self._urlClickedSlot)
self.connect(self.uiWebView, QtCore.SIGNAL('loadFinished(bool)'), self._loadFinishedSlot)
self.adjustSize()
self._timer = QtCore.QTimer()
self.connect(self._timer, QtCore.SIGNAL('timeout()'), self._refreshSlot)
self._timer.start(10000) # refresh every 10 seconds
self.loadWebPage()
def done(self, result):
self._timer.stop()
QtGui.QDialog.done(self, result)
def _refreshSlot(self):
self.uiWebView.reload()
def loadWebPage(self):
self.uiWebView.load(self.webpage)
def _urlClickedSlot(self, url):
if QtGui.QDesktopServices.openUrl(url) == False:
print("Failed to open the URL: {}".format(url))
def _loadFinishedSlot(self, result):
self.disconnect(self.uiWebView, QtCore.SIGNAL('loadFinished(bool)'), self._loadFinishedSlot)
if result == False:
QtGui.QMessageBox.information(self, "News", "Cannot load the online page, trying with your default browser ...")
if QtGui.QDesktopServices.openUrl(self.webpage) == False:
print("Failed to open the URL: {}".format(self.webpage.toString()))
self.uiDontShowAgainCheckBox.setChecked(True)
self.close()

3201
gns3/ui/about_dialog.ui Executable file

File diff suppressed because it is too large Load Diff

3141
gns3/ui/about_dialog_ui.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EarlyReleaseDialog</class>
<widget class="QDialog" name="EarlyReleaseDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>467</width>
<height>285</height>
</rect>
</property>
<property name="windowTitle">
<string>GNS3 Early Release</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="1">
<widget class="QLineEdit" name="uiEmailLineEdit"/>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="uiEmailLabel">
<property name="text">
<string>Email address:</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Disclaimer</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="uiDisclaimerLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This is an alpha release of the new GNS3, please do not use it&lt;br&gt;for production or any important work. Bugs are very likely and&lt;br&gt;existing features can change without warning until the beta&lt;br&gt;release cycle starts. Thank you for your understanding!
&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="uiDisclaimerCheckBox">
<property name="text">
<string>I understand</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="uiUsernameLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="uiUsernameLabel">
<property name="text">
<string>GNS3 username:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This is a early release of the new GNS3, you need a GNS3 membership&lt;br&gt;in order to use it. Please visit our &lt;a href=&quot;http://new.gns3.net&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;crowdfunding page&lt;/span&gt;&lt;/a&gt; to get one.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>uiUsernameLineEdit</tabstop>
<tabstop>uiEmailLineEdit</tabstop>
<tabstop>uiDisclaimerCheckBox</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>EarlyReleaseDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>EarlyReleaseDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,85 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/home/grossmj/workspace/git/gns3-gui/gns3/ui/early_release_dialog.ui'
#
# Created: Wed Mar 19 16:26:12 2014
# by: PyQt4 UI code generator 4.10
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_EarlyReleaseDialog(object):
def setupUi(self, EarlyReleaseDialog):
EarlyReleaseDialog.setObjectName(_fromUtf8("EarlyReleaseDialog"))
EarlyReleaseDialog.resize(467, 285)
EarlyReleaseDialog.setModal(True)
self.gridLayout_2 = QtGui.QGridLayout(EarlyReleaseDialog)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.uiEmailLineEdit = QtGui.QLineEdit(EarlyReleaseDialog)
self.uiEmailLineEdit.setObjectName(_fromUtf8("uiEmailLineEdit"))
self.gridLayout_2.addWidget(self.uiEmailLineEdit, 2, 1, 1, 1)
spacerItem = QtGui.QSpacerItem(20, 4, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem, 4, 1, 1, 1)
self.buttonBox = QtGui.QDialogButtonBox(EarlyReleaseDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.gridLayout_2.addWidget(self.buttonBox, 5, 1, 1, 1)
self.uiEmailLabel = QtGui.QLabel(EarlyReleaseDialog)
self.uiEmailLabel.setObjectName(_fromUtf8("uiEmailLabel"))
self.gridLayout_2.addWidget(self.uiEmailLabel, 2, 0, 1, 1)
self.groupBox = QtGui.QGroupBox(EarlyReleaseDialog)
self.groupBox.setObjectName(_fromUtf8("groupBox"))
self.gridLayout = QtGui.QGridLayout(self.groupBox)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.uiDisclaimerLabel = QtGui.QLabel(self.groupBox)
self.uiDisclaimerLabel.setObjectName(_fromUtf8("uiDisclaimerLabel"))
self.gridLayout.addWidget(self.uiDisclaimerLabel, 0, 0, 1, 2)
self.uiDisclaimerCheckBox = QtGui.QCheckBox(self.groupBox)
self.uiDisclaimerCheckBox.setObjectName(_fromUtf8("uiDisclaimerCheckBox"))
self.gridLayout.addWidget(self.uiDisclaimerCheckBox, 1, 0, 1, 1)
self.gridLayout_2.addWidget(self.groupBox, 3, 0, 1, 2)
self.uiUsernameLineEdit = QtGui.QLineEdit(EarlyReleaseDialog)
self.uiUsernameLineEdit.setObjectName(_fromUtf8("uiUsernameLineEdit"))
self.gridLayout_2.addWidget(self.uiUsernameLineEdit, 1, 1, 1, 1)
self.uiUsernameLabel = QtGui.QLabel(EarlyReleaseDialog)
self.uiUsernameLabel.setObjectName(_fromUtf8("uiUsernameLabel"))
self.gridLayout_2.addWidget(self.uiUsernameLabel, 1, 0, 1, 1)
self.label = QtGui.QLabel(EarlyReleaseDialog)
self.label.setOpenExternalLinks(True)
self.label.setObjectName(_fromUtf8("label"))
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 2)
self.retranslateUi(EarlyReleaseDialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EarlyReleaseDialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EarlyReleaseDialog.reject)
QtCore.QMetaObject.connectSlotsByName(EarlyReleaseDialog)
EarlyReleaseDialog.setTabOrder(self.uiUsernameLineEdit, self.uiEmailLineEdit)
EarlyReleaseDialog.setTabOrder(self.uiEmailLineEdit, self.uiDisclaimerCheckBox)
EarlyReleaseDialog.setTabOrder(self.uiDisclaimerCheckBox, self.buttonBox)
def retranslateUi(self, EarlyReleaseDialog):
EarlyReleaseDialog.setWindowTitle(_translate("EarlyReleaseDialog", "GNS3 Early Release", None))
self.uiEmailLabel.setText(_translate("EarlyReleaseDialog", "Email address:", None))
self.groupBox.setTitle(_translate("EarlyReleaseDialog", "Disclaimer", None))
self.uiDisclaimerLabel.setText(_translate("EarlyReleaseDialog", "<html><head/><body><p>This is an alpha release of the new GNS3, please do not use it<br>for production or any important work. Bugs are very likely and<br>existing features can change without warning until the beta<br>release cycle starts. Thank you for your understanding!\n"
"</p></body></html>", None))
self.uiDisclaimerCheckBox.setText(_translate("EarlyReleaseDialog", "I understand", None))
self.uiUsernameLabel.setText(_translate("EarlyReleaseDialog", "GNS3 username:", None))
self.label.setText(_translate("EarlyReleaseDialog", "<html><head/><body><p>This is a early release of the new GNS3, you need a GNS3 membership<br>in order to use it. Please visit our <a href=\"http://new.gns3.net\"><span style=\" text-decoration: underline; color:#0000ff;\">crowdfunding page</span></a> to get one.</p></body></html>", None))

141
gns3/ui/news_dialog.ui Normal file
View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewsDialog</class>
<widget class="QDialog" name="NewsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>424</width>
<height>466</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>GNS3 News</string>
</property>
<widget class="QWebView" name="uiWebView" native="true">
<property name="geometry">
<rect>
<x>12</x>
<y>12</y>
<width>400</width>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>400</height>
</size>
</property>
<property name="url" stdset="0">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>12</x>
<y>420</y>
<width>401</width>
<height>32</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="uiWhyThisAdLabel">
<property name="text">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body&gt;
&lt;p&gt; &lt;a href=&quot;http://www.gns3.net/why-this-ad/&quot;&gt;Why this?&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>58</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>QWebView</class>
<extends>QWidget</extends>
<header>QtWebKit/QWebView</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>NewsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NewsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

72
gns3/ui/news_dialog_ui.py Normal file
View File

@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/home/grossmj/workspace/git/gns3-gui/gns3/ui/news_dialog.ui'
#
# Created: Wed Mar 19 16:26:12 2014
# by: PyQt4 UI code generator 4.10
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_NewsDialog(object):
def setupUi(self, NewsDialog):
NewsDialog.setObjectName(_fromUtf8("NewsDialog"))
NewsDialog.resize(424, 466)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(NewsDialog.sizePolicy().hasHeightForWidth())
NewsDialog.setSizePolicy(sizePolicy)
self.uiWebView = QtWebKit.QWebView(NewsDialog)
self.uiWebView.setGeometry(QtCore.QRect(12, 12, 400, 400))
self.uiWebView.setMinimumSize(QtCore.QSize(400, 400))
self.uiWebView.setMaximumSize(QtCore.QSize(400, 400))
self.uiWebView.setProperty("url", QtCore.QUrl(_fromUtf8("about:blank")))
self.uiWebView.setObjectName(_fromUtf8("uiWebView"))
self.layoutWidget = QtGui.QWidget(NewsDialog)
self.layoutWidget.setGeometry(QtCore.QRect(12, 420, 401, 32))
self.layoutWidget.setObjectName(_fromUtf8("layoutWidget"))
self.horizontalLayout = QtGui.QHBoxLayout(self.layoutWidget)
self.horizontalLayout.setMargin(0)
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
self.uiWhyThisAdLabel = QtGui.QLabel(self.layoutWidget)
self.uiWhyThisAdLabel.setOpenExternalLinks(True)
self.uiWhyThisAdLabel.setObjectName(_fromUtf8("uiWhyThisAdLabel"))
self.horizontalLayout.addWidget(self.uiWhyThisAdLabel)
spacerItem = QtGui.QSpacerItem(58, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.buttonBox = QtGui.QDialogButtonBox(self.layoutWidget)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
self.horizontalLayout.addWidget(self.buttonBox)
self.retranslateUi(NewsDialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), NewsDialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), NewsDialog.reject)
QtCore.QMetaObject.connectSlotsByName(NewsDialog)
def retranslateUi(self, NewsDialog):
NewsDialog.setWindowTitle(_translate("NewsDialog", "GNS3 News", None))
self.uiWhyThisAdLabel.setText(_translate("NewsDialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body>\n"
"<p> <a href=\"http://www.gns3.net/why-this-ad/\">Why this?</a></p></body></html>", None))
from PyQt4 import QtWebKit

View File

@@ -25,5 +25,5 @@ or negative for a release candidate or beta (after the base version
number has been incremented)
"""
__version__ = "0.9.dev"
__version_info__ = (0, 9, 0, -99)
__version__ = "1.0-alpha1"
__version_info__ = (1, 0, 0, -99)

View File

@@ -161,8 +161,13 @@ class WebSocketClient(WebSocketBaseClient):
method = reply.get("method")
params = reply.get("params")
#TODO: handle notifications from servers
print("This is a notification! {} {}".format(method, params))
# let the responsible module know about the notification
from .modules import MODULES
for module in MODULES:
if method.startswith(module.__name__.lower()):
instance = module.instance()
instance.notification(method, params)
break
def send_message(self, destination, params, callback):
"""