2014-01-31 16:22:31 -07:00
# -*- 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/>.
"""
Nodes view that list all the available nodes to be dragged and dropped on the QGraphics scene .
"""
import pickle
2016-09-06 14:48:04 +02:00
import sip
2016-02-10 15:11:21 +01:00
from . qt import QtCore , QtGui , QtWidgets , qpartial
2014-03-11 16:44:37 -06:00
from . modules import MODULES
2016-07-18 18:37:03 +02:00
from . node import Node
2016-09-06 14:48:04 +02:00
from . controller import Controller
2016-02-03 18:09:20 +01:00
from . dialogs . configuration_dialog import ConfigurationDialog
2014-01-31 16:22:31 -07:00
2015-04-17 12:14:21 +02:00
class NodesView ( QtWidgets . QTreeWidget ) :
2015-01-28 11:13:10 +01:00
2014-01-31 16:22:31 -07:00
"""
Nodes view to list the nodes .
: param parent : parent widget
"""
def __init__ ( self , parent = None ) :
2015-04-17 12:14:21 +02:00
super ( ) . __init__ ( parent )
2015-05-28 16:54:39 +02:00
self . _current_category = None
2014-01-31 16:22:31 -07:00
# enables the possibility to drag items.
self . setDragEnabled ( True )
2016-09-06 14:48:04 +02:00
Controller . instance ( ) . connected_signal . connect ( self . refresh )
2015-05-28 16:54:39 +02:00
def refresh ( self ) :
2015-08-04 17:51:31 +02:00
self . clear ( )
2015-08-04 17:58:47 +02:00
self . populateNodesView ( self . _current_category )
2015-05-28 16:54:39 +02:00
2015-08-04 17:58:47 +02:00
def populateNodesView ( self , category ) :
2014-03-24 21:06:56 -06:00
"""
Populates the nodes view with the device list of the specified
category ( None = all devices ) .
: param category : category of device to list
"""
2016-09-06 14:48:04 +02:00
if not Controller . instance ( ) . connected ( ) :
return
2015-05-28 16:54:39 +02:00
self . _current_category = category
2014-03-11 16:44:37 -06:00
for module in MODULES :
2014-09-23 17:43:59 -06:00
for node in module . instance ( ) . nodes ( ) :
if category is not None and category not in node [ " categories " ] :
2014-03-24 21:06:56 -06:00
continue
2015-04-17 12:14:21 +02:00
item = QtWidgets . QTreeWidgetItem ( self )
2014-09-23 17:43:59 -06:00
item . setText ( 0 , node [ " name " ] )
2014-03-11 16:44:37 -06:00
item . setData ( 0 , QtCore . Qt . UserRole , node )
2016-09-06 17:57:31 +02:00
item . setSizeHint ( 0 , QtCore . QSize ( 32 , 32 ) )
2016-09-06 14:48:04 +02:00
Controller . instance ( ) . getSymbolIcon ( node [ " symbol " ] , qpartial ( self . _setItemIcon , item ) )
2014-01-31 16:22:31 -07:00
2016-07-13 17:37:52 +02:00
if not self . topLevelItemCount ( ) and category == Node . routers :
QtWidgets . QMessageBox . warning ( self , ' Routers ' , ' No routers have been configured.<br>You must provide your own router images in order to use GNS3.<br><br><a href= " https://gns3.com/support/docs " >Show documentation</a> ' )
2014-10-13 19:53:17 -06:00
self . sortByColumn ( 0 , QtCore . Qt . AscendingOrder )
2016-09-06 14:48:04 +02:00
def _setItemIcon ( self , item , icon ) :
if not sip . isdeleted ( item ) :
item . setIcon ( 0 , icon )
2016-02-03 18:09:20 +01:00
def mousePressEvent ( self , event ) :
"""
Handles all mouse press events .
: param : QMouseEvent instance
"""
# Check that an item has been selected and right click
if self . currentItem ( ) is not None and event . button ( ) == QtCore . Qt . RightButton :
self . _showContextualMenu ( )
event . accept ( )
return
super ( ) . mousePressEvent ( event )
2014-01-31 16:22:31 -07:00
def mouseMoveEvent ( self , event ) :
"""
Handles all mouse move events .
This is the starting point to drag & drop a node on the scene .
2014-02-27 21:45:56 -07:00
: param : QMouseEvent instance
2014-01-31 16:22:31 -07:00
"""
2016-02-03 18:09:20 +01:00
# Check that an item has been selected and left button clicked
if self . currentItem ( ) is not None and event . buttons ( ) == QtCore . Qt . LeftButton :
item = self . currentItem ( )
icon = item . icon ( 0 )
# retrieve the node class from the item data
node = item . data ( 0 , QtCore . Qt . UserRole )
mimedata = QtCore . QMimeData ( )
# pickle the node class, set the Mime type and data
# and start dragging the item.
data = pickle . dumps ( node )
mimedata . setData ( " application/x-gns3-node " , data )
drag = QtGui . QDrag ( self )
drag . setMimeData ( mimedata )
drag . setPixmap ( icon . pixmap ( self . iconSize ( ) ) )
drag . setHotSpot ( QtCore . QPoint ( drag . pixmap ( ) . width ( ) , drag . pixmap ( ) . height ( ) ) )
drag . exec_ ( QtCore . Qt . CopyAction )
event . accept ( )
def _showContextualMenu ( self ) :
2014-01-31 16:22:31 -07:00
item = self . currentItem ( )
node = item . data ( 0 , QtCore . Qt . UserRole )
2016-02-03 18:09:20 +01:00
node_module = None
for module in MODULES :
node_class = module . getNodeClass ( node [ " class " ] )
if node_class :
break
2016-02-04 16:24:17 +01:00
# We can not edit stuff like EthernetSwitch
# or without config template like VPCS
if not " builtin " in node and hasattr ( module , " vmConfigurationPage " ) :
2016-02-03 18:09:20 +01:00
for vm_key , vm in module . instance ( ) . VMs ( ) . items ( ) :
if vm [ " name " ] == node [ " name " ] :
break
menu = QtWidgets . QMenu ( )
2016-02-03 12:28:09 -07:00
configuration = QtWidgets . QAction ( " Configure Template " , menu )
2016-02-03 18:09:20 +01:00
configuration . setIcon ( QtGui . QIcon ( " :/icons/configuration.svg " ) )
configuration . triggered . connect ( qpartial ( self . _configurationSlot , vm , module ) )
menu . addAction ( configuration )
2016-02-03 12:28:09 -07:00
configuration = QtWidgets . QAction ( " Delete Template " , menu )
2016-02-03 18:09:20 +01:00
configuration . setIcon ( QtGui . QIcon ( " :/icons/delete.svg " ) )
configuration . triggered . connect ( qpartial ( self . _deleteSlot , vm_key , vm , module ) )
menu . addAction ( configuration )
menu . exec_ ( QtGui . QCursor . pos ( ) )
def _configurationSlot ( self , vm , module , source ) :
dialog = ConfigurationDialog ( vm [ " name " ] , vm , module . vmConfigurationPage ( ) ( ) , parent = self )
dialog . show ( )
if dialog . exec_ ( ) :
module . instance ( ) . setVMs ( module . instance ( ) . VMs ( ) )
self . refresh ( )
def _deleteSlot ( self , vm_key , vm , module , source ) :
2016-02-03 12:28:09 -07:00
reply = QtWidgets . QMessageBox . question ( self , " Template " , " Delete {} template? " . format ( vm [ " name " ] ) ,
QtWidgets . QMessageBox . Yes , QtWidgets . QMessageBox . No )
2016-02-03 18:09:20 +01:00
if reply == QtWidgets . QMessageBox . Yes :
vms = module . instance ( ) . VMs ( )
vms . pop ( vm_key )
module . instance ( ) . setVMs ( vms )
self . refresh ( )