diff --git a/INSTALL b/INSTALL index f1233d73..572fdb9d 100644 --- a/INSTALL +++ b/INSTALL @@ -1,13 +1,67 @@ Installation ============ -To install SocNetV 1.x you need Qt5 development libraries. Qt is a C++ toolkit published under GPL. Most modern Linux distros, especially those providing KDE as their default desktop environment, include Qt. So if you have one of openSUSE, Mandriva, Fedora, Kubuntu, Slackware, etc, you dont need to download Qt. It should be already installed. +Binaries -If you have Qt5 installed, all you have to do is to type in the following commands in order to decompress the SocNetV tarball and build it. Replace 1.X with the versionyou downloaded... +SocNetV binary packages are available for Windows, Mac OS X and Linux distros. -1) untar zxfv SocNetV-1.X.tar.gz +You can download a binary package for your Operating System from the project +webpage at: http://socnetv.sourceforge.net/downloads -2) cd socnetv-1.X +If there is no package for your OS, please download and compile the source code. + +Windows + +To run SocNetV in Windows, download the latest SocNetV zip for Windows from the +Downloads page, unzip it, and double-click on the socnetv executable. +The program will run immediately. + +Mac OS X + +If you are a Mac user, you can download and run SocNetV from a disk image (dmg file). +From the Downloads page, download the Mac OS .dmg file. +Once downloaded, double click on it and a new window will appear. +To run the application, double click on the SocNetV icon holding down the META key. +To install SocNetV, drag the SocNetV icon to your Applications. + +Linux + +SocNetV is available in most Linux distributions, although not the latest version. + +To install the latest and greatest SocNetV version, users of openSUSE, Fedora and +Ubuntu/Debian are advised to add our own repositories to their systems. + +In Debian and Ubuntu, install SocNetV from our repos with these commands: + +sudo add-apt-repository ppa:dimitris-kalamaras/ppa +sudo apt-get update +sudo apt-get install socnetv + +In Fedora and openSUSE, choose and add the correct repository from here: +http://download.opensuse.org/repositories/home:/oxy86/ + +Once you add the repo, install SocNetV using the command (Fedora): +sudo yum install socnetv + +or (openSUSE): +sudo zypper in socnetv + + +Compile from source code + +To compile and install SocNetV from source you need the Qt5 toolkit +development libraries. Qt is an open source C++ toolkit published under the GPL. +Qt5 is preinstalled in most Linux distributions and it is available for +Windows and Mac OS X. If you do not have Qt5 installed, please download and +install it from https://www.qt.io/developers + +Once you have Qt5 installed in your OS, you are ready to compile SocNetV from source. +All you have to do is to type in the following commands in order to decompress the +SocNetV tarball and build it. Replace 2.X with the version you downloaded. + +1) untar zxfv SocNetV-2.X.tar.gz + +2) cd socnetv-2.X 3) qmake @@ -16,7 +70,6 @@ If you have Qt5 installed, all you have to do is to type in the following comman 5) sudo make install Probably you have already done the first 2 steps, so just type in 'qmake' or 'qmake-qt5'. -If Qt5 is not installed, the script will let you know... When you finish compiling and installing, run the application typing: diff --git a/NEWS b/NEWS index e141546b..5f14e3bf 100644 --- a/NEWS +++ b/NEWS @@ -4,11 +4,14 @@ Social Networks Visualiser (SocNetV) SocNetV News -==========- -July 2015 -========= -- Version 2.0 development starts. -- New doxygen source documentation -- New Windows Installer +Sep 2016 +======== + - Version 2.0 released with major code overhaul, new GUI layout and lots of bugfixes and improvements. + The new version brings stability, great performance boost, and nice new features such as separate modes + for graphs and digraphs, permanent settings/preferences functionality, edge labeling, recent files, + keyboard shortcuts, etc. Also there are improvements in Force-Directed layouts, i.e. Fructherman-Reingold. + See ChangeLog for a complete overview of the new features. +- The SocNetV Manual is now build with Doxygen and it is available at http://socnetv.sf.net/documentation June 2015 ========= diff --git a/README.md b/README.md index 650df23b..e3c4c76f 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,10 @@ The documentation is also Free, licensed under the Free Documentation License (F Official Website: http://socnetv.sourceforge.net Author: Dimitris V. Kalamaras -My Blog: http://dimitris.apeiro.gr +Blog: http://dimitris.apeiro.gr SocNetV is a cross-platform application, developed in C++ language -using the Qt5 multiplatform library and tools. +using the Qt5 cross-platform libraries and tools. This means you can compile and run SocNetV on Linux, Mac and Windows. @@ -79,75 +79,92 @@ See section 6 (bug reporting) below. 3. Installation --------------- -You can install SocNetV by: +You can install SocNetV : -a) compiling it from source or b) using binary packages. +a) compiling it from source or -In either case, you need Qt 5 for versions 1.x -Most Linux Distros have Qt installed by default. -Windows and OS X users please go to http://qt-project.org to download Qt5 library. - -If you cannot install Qt5 you can try the 0.x series of SocNetV which work with Qt4. -Please note that SocNetV uses QtWebKit to display online help. -QtWebKit has been added to Qt from version 4.4, which means you can't compile -SocNetV in distros with older releases of Qt. +## a) Install a binary package or executable (Linux/Mac/Windows) -## a) Compile from Source Code - -To compile from source code, download the tarball archive with the source code -of the latest SocNetV version (you probably already have this :P). -Then, untar (decompress) the archive using a command like this: +SocNetV binary packages are available for Windows, Mac OS X and Linux distros. -tar zxfv SocNetV-1.X.tar.gz +You can download a binary package for your Operating System from the project +webpage at: http://socnetv.sourceforge.net/downloads -Then enter the new directory and compile with these commands: +If there is no package for your OS, please download and compile the source code. -cd socnetv-1.XX -qmake (or qmake-qt5) -make +Windows -Now you can install it using: +To run SocNetV in Windows, download the latest SocNetV zip for Windows from the +Downloads page, unzip it, and double-click on the socnetv executable. +The program will run immediately. -su -c 'make install' +Mac OS X -or +If you are a Mac user, you can download and run SocNetV from a disk image (dmg file). +From the Downloads page, download the Mac OS .dmg file. +Once downloaded, double click on it and a new window will appear. +To run the application, double click on the SocNetV icon holding down the META key. +To install SocNetV, drag the SocNetV icon to your Applications. -sudo make install +Linux -If everything is ok, then you can run SocNetV by entering: +SocNetV is available in most Linux distributions, although not the latest version. -socnetv +To install the latest and greatest SocNetV version, users of openSUSE, Fedora and +Ubuntu/Debian are advised to add our own repositories to their systems. +In Debian and Ubuntu, install SocNetV from our repos with these commands: -## b) Install a binary package or executable (Linux/Mac/Windows) +sudo add-apt-repository ppa:dimitris-kalamaras/ppa +sudo apt-get update +sudo apt-get install socnetv -To install SocNetV from a binary package for Linux or an executable for -Windows, check http://socnetv.sourceforge.net/downloads.html and see if -there is a package of the latest version for your operating system. +In Fedora and openSUSE, choose and add the correct repository from here: +http://download.opensuse.org/repositories/home:/oxy86/ -Please note that SocNetV is also available in most Linux distributions, -although not always the latest version. +Once you add the repo, install SocNetV using the command (Fedora): +sudo yum install socnetv -In Debian and Ubuntu, install SocNetV from repos with: +or (openSUSE): +sudo zypper in socnetv -sudo apt-get install socnetv -In Fedora, use the command: -sudo yum install socnetv -In openSUSE: -sudo zypper in socnetv +## b) Compile from Source Code + +To compile and install SocNetV from source you need the Qt5 toolkit development +libraries. Qt is an open source C++ toolkit published under the GPL. +Qt5 is preinstalled in most Linux distributions and it is available for +Windows and Mac OS X. If you do not have Qt5 installed, please download and +install it from https://www.qt.io/developers + +Once you have Qt5 installed in your OS, you are ready to compile SocNetV from source. +Download the tarball archive with the source code of the latest SocNetV version +(you probably already have this :P). + +All you have to do is to type in the following commands in order to decompress the +SocNetV tarball and build it. Replace 2.X with the version you downloaded. -Mac OS users may download the disk image of the latest version from -http://socnetv.sourceforge.net/downloads.html. +1) untar zxfv SocNetV-2.X.tar.gz -Double click on the .img file, then on the new window click socnetv icon -while pressing down the meta key. +2) cd socnetv-2.X + +3) qmake + +4) make + +5) sudo make install or su -c 'make install' + +Probably you have already done the first 2 steps, so just type in 'qmake' or 'qmake-qt5'. + +When you finish compiling and installing, run the application typing: + +socnetv + +or go to Start Menu > Mathematics > SocNetV. -You can also find versions for Mac on the Internet, although these are -not supported. See: http://pdb.finkproject.org/pdb/package.php/socnetv-mac # 4. Command Line Options @@ -155,13 +172,9 @@ not supported. See: http://pdb.finkproject.org/pdb/package.php/socnetv-mac SocNetV is primarily a GUI program. Nevertheless, some command line options are available. Type: -1) ./socnetv filename.net - to start snv with network named filename.net loaded. -2) ./socnetv -v - to print version of snv and exit. -3) ./socnetv -d - to enable debugging mode, in which snv prints comprehensive messages about - what it is doing. +./socnetv filename.net + +to start socnetv with network named filename.net loaded. @@ -171,9 +184,6 @@ For usage documentation, see online help. Or, when running SocNetV, press F1 to display the SocNetV Manual. -There are some example networks inside the /usr/local/doc/socnetv/net folder. -Just press Ctrl+O, go there and choose one file. - # 6. Bug reporting diff --git a/TODO b/TODO index 13deb258..9002b787 100644 --- a/TODO +++ b/TODO @@ -3,12 +3,9 @@ KNOWN BUGS 1: Negative weights break centralities 2: UCINET (DL) files in nodelist1 format (one-mode) are not supported. -3: isSymmetric() not 100% (check a-symmetry.net) -4: Some Graphviz (dot) files do not load. See test2.dot. Cant read when one line and nodes dont appear... -7: SocNetV cannot load GraphML files with node labels which contain the & character. -8: 2014-02-28: In Reciprocal links with diferrent weight, only the first weight is taken into account -9: closeness reports wrong indices in digraphs, where one actor has only one outLink -10: fix other related indices for digraphs when d(i,j) = inf +3: Some Graphviz (dot) files do not load. See test2.dot. Cant read when one line and nodes dont appear... +4: closeness reports wrong indices in digraphs, where one actor has only one outLink +5: fix other related indices for digraphs when d(i,j) = inf TODO diff --git a/changelog.gz b/changelog.gz index 5cfda4aa..94e4ba4b 100755 Binary files a/changelog.gz and b/changelog.gz differ diff --git a/debian/changelog b/debian/changelog index 5e249497..83c9373e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,8 @@ -socnetv (2.0-1-dev) trusty; urgency=medium +socnetv (2.0-1) trusty; urgency=medium - * Development 2.0 snapshots + * New upstream version 1.9. See http://socnetv.sf.net/ChangeLog - -- Dimitris V. Kalamaras Thu, 25 Jun 2015 10:13:03 +0300 + -- Dimitris V. Kalamaras Mon, 12 Sep 2016 10:13:03 +0300 socnetv (1.9-3) trusty; urgency=medium diff --git a/debian/copyright b/debian/copyright index ba7c49da..e1406572 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,10 +1,9 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: socnetv -Upstream-Contact: Dimitris Kalamaras Source: http://socnetv.sf.net Files: * -Copyright: 2004-2014 Dimitris Kalamaras +Copyright: 2004-2016 Dimitris Kalamaras License: GPL-3 Files: debian/* @@ -12,5 +11,18 @@ Copyright: 2014-2014 Dimitris Kalamaras License: GPL-3 License: GPL-3 + 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 package 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 . + . On Debian systems, the complete text of the GNU General Public License can be found in the file /usr/share/common-licenses/GPL-3. diff --git a/doxyfile b/doxyfile index 9218210d..5ef34d47 100644 --- a/doxyfile +++ b/doxyfile @@ -51,14 +51,14 @@ PROJECT_BRIEF = "Social Network Visualization and Analysis Software" # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = ../logo/socnetv-logo-doxygen.png +PROJECT_LOGO = ./src/manual/socnetv-logo-manual.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = ./doc +OUTPUT_DIRECTORY = ./manual # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -409,7 +409,7 @@ LOOKUP_CACHE_SIZE = 0 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = NO +EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. @@ -758,7 +758,7 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = src/ ./manual/manual.txt ./manual/intro.txt ./manual/gui.txt ./manual/generate.txt ./manual/formats.txt ./manual/analysis.txt ./manual/visualisation.txt ./manual/bugs.txt ./manual/credits.txt +INPUT = src/ ./src/manual/manual.txt ./src/manual/intro.txt ./src/manual/gui.txt ./src/manual/generate.txt ./src/manual/formats.txt ./src/manual/analysis.txt ./src/manual/visualisation.txt ./src/manual/bugs.txt ./src/manual/credits.txt @@ -848,7 +848,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = ./manual +IMAGE_PATH = ./src/manual # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -1025,7 +1025,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = html +HTML_OUTPUT = . # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). @@ -1052,7 +1052,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = src/manual/header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1062,7 +1062,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = src/manual/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1074,7 +1074,7 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets @@ -1087,7 +1087,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = src/manual/socnetv.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1465,7 +1465,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = ./manual/mathjaxconfig.js +MATHJAX_CODEFILE = ./src/manual/mathjaxconfig.js # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and diff --git a/man/socnetv.1.gz b/man/socnetv.1.gz index 1c766647..1426e292 100644 Binary files a/man/socnetv.1.gz and b/man/socnetv.1.gz differ diff --git a/manual/header.html b/manual/header.html deleted file mode 100644 index d7b0aae1..00000000 --- a/manual/header.html +++ /dev/null @@ -1,15 +0,0 @@ - - -
- -

The SocNetV Manual

-
- diff --git a/manual/manual.html b/manual/manual.html deleted file mode 100644 index 8e86ac03..00000000 --- a/manual/manual.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - SocNetV Handbook - - - - - - - - - - - - - - diff --git a/manual/socnetv-analysis.jpg b/manual/socnetv-analysis.jpg deleted file mode 100644 index 5fb82ead..00000000 Binary files a/manual/socnetv-analysis.jpg and /dev/null differ diff --git a/manual/socnetv-main-window-annotated-2.png b/manual/socnetv-main-window-annotated-2.png deleted file mode 100644 index d5433e31..00000000 Binary files a/manual/socnetv-main-window-annotated-2.png and /dev/null differ diff --git a/manual/socnetv-main-window-annotated.png b/manual/socnetv-main-window-annotated.png deleted file mode 100644 index 96815dc9..00000000 Binary files a/manual/socnetv-main-window-annotated.png and /dev/null differ diff --git a/socnetv.pro b/socnetv.pro index 10af0621..c21801e1 100755 --- a/socnetv.pro +++ b/socnetv.pro @@ -46,12 +46,14 @@ FORMS += src/forms/filteredgesbyweightdialog.ui \ src/forms/datasetselectdialog.ui \ src/forms/randsmallworlddialog.ui \ src/forms/randscalefreedialog.ui \ - src/forms/randerdosrenyidialog.ui + src/forms/randerdosrenyidialog.ui \ + src/forms/settingsdialog.ui HEADERS += src/guide.h \ src/graphicswidget.h \ src/edge.h \ src/edgeweight.h \ + src/edgelabel.h \ src/graph.h \ src/mainwindow.h \ src/matrix.h \ @@ -69,12 +71,14 @@ HEADERS += src/guide.h \ src/nodeeditdialog.h \ src/randerdosrenyidialog.h \ src/randsmallworlddialog.h \ - src/randscalefreedialog.h + src/randscalefreedialog.h \ + src/settingsdialog.h SOURCES += src/guide.cpp \ src/graphicswidget.cpp \ src/edge.cpp \ src/edgeweight.cpp \ + src/edgelabel.cpp \ src/graph.cpp \ src/main.cpp \ src/mainwindow.cpp \ @@ -93,20 +97,21 @@ SOURCES += src/guide.cpp \ src/nodeeditdialog.cpp \ src/randerdosrenyidialog.cpp \ src/randsmallworlddialog.cpp \ - src/randscalefreedialog.cpp + src/randscalefreedialog.cpp \ + src/settingsdialog.cpp # Extra optimization flags -win32 { - QMAKE_CXXFLAGS += -msse -mfpmath=sse -ffast-math -} -unix:!macx{ - QMAKE_CXXFLAGS += -ffast-math -} -macx { - QMAKE_CXXFLAGS += -msse -ffast-math -} +#win32 { +# QMAKE_CXXFLAGS += -msse -mfpmath=sse -ffast-math +#} +#unix:!macx{ +# QMAKE_CXXFLAGS += -ffast-math +#} +#macx { +# QMAKE_CXXFLAGS += -msse -ffast-math +#} INCLUDEPATH += /usr/local/include /usr/include /usr/include/qt5 /usr/share/qt5/include INCLUDEPATH += /usr/local/include /usr/include /usr/include/qt /usr/include/qt5 /usr/share/qt5/include diff --git a/socnetv.spec b/socnetv.spec index 61fbc6d6..a2f4661b 100644 --- a/socnetv.spec +++ b/socnetv.spec @@ -1,6 +1,6 @@ # spec file for package socnetv # -# Copyright (c) 2014 Dimitris Kalamaras dimitris.kalamaras@gmail.com +# Copyright (c) 2016 Dimitris Kalamaras dimitris.kalamaras@gmail.com # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -46,7 +46,7 @@ %if %{is_fedora} %define distr Fedora -%define breqr qt5-qtbase,qt5-qtbase-devel, qt5-qttools, qt5-qtwebkit, qt5-qtwebkit-devel, fedora-release, desktop-file-utils +%define breqr qt5-qtbase,qt5-qtbase-devel, qt5-qttools, fedora-release, desktop-file-utils %define qmake /usr/bin/qmake-qt5 %define lrelease /usr/bin/lrelease %endif @@ -55,7 +55,7 @@ %if %{is_suse} %define distr SUSE # %(head -1 /etc/SuSE-release) -%define breqr libqt5-qtbase, libqt5-qtbase-devel, libqt5-qttools, libQt5WebKit5, libQt5WebKit5-devel, update-desktop-files +%define breqr libqt5-qtbase, libqt5-qtbase-devel, libqt5-qttools, update-desktop-files %define qmake /usr/bin/qmake-qt5 %define lrelease /usr/bin/lrelease %endif @@ -71,7 +71,6 @@ License: GPL-3.0 Group: Productivity/Scientific/Math URL: http://socnetv.sourceforge.net/ Vendor: Dimitris V. Kalamaras -#Packager: Dimitris V. Kalamaras # Removed for OBS warnings... Source0: SocNetV-%{version}.tar.bz2 Distribution: %{distr} Prefix: %{prefix} @@ -81,7 +80,6 @@ BuildRequires: pkgconfig(Qt5Gui) BuildRequires: pkgconfig(Qt5PrintSupport) BuildRequires: pkgconfig(Qt5Widgets) BuildRequires: pkgconfig(Qt5Network) -#BuildRequires: pkgconfig(Qt5WebKitWidgets) BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot @@ -180,8 +178,8 @@ rm -rf %{buildroot}/%{_datadir}/doc/%{name} #CHANGELOG SECTION # %changelog -* Fri Jul 31 2015 Dimitris Kalamaras - 2.0-1 -- Synced with DEV version from upstream. +* Mon Sep 12 2016 Dimitris Kalamaras - 2.0-1 +- Synced with new stable version from upstream. * Tue Jun 23 2015 Dimitris Kalamaras - 1.9-1 - Synced with DEV version from upstream. * Fri Jun 05 2015 Dimitris Kalamaras - 1.8-1 diff --git a/src/datasetselectdialog.cpp b/src/datasetselectdialog.cpp index 6afc7813..6c4dac60 100755 --- a/src/datasetselectdialog.cpp +++ b/src/datasetselectdialog.cpp @@ -5,7 +5,7 @@ datasetselectdialog.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ diff --git a/src/datasetselectdialog.h b/src/datasetselectdialog.h index d175b3a2..06b38422 100755 --- a/src/datasetselectdialog.h +++ b/src/datasetselectdialog.h @@ -5,7 +5,7 @@ datasetselectdialog.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ diff --git a/src/edge.cpp b/src/edge.cpp index dc7afa4e..0fa9452e 100755 --- a/src/edge.cpp +++ b/src/edge.cpp @@ -5,7 +5,7 @@ edge.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -35,26 +35,29 @@ #include "edge.h" #include "node.h" #include "edgeweight.h" +#include "edgelabel.h" static const double Pi = 3.14159265; static double TwoPi = 2.0 * Pi; +static const int EDGE_DIRECTED = 0; +static const int EDGE_DIRECTED_OPPOSITE_EXISTS = 1; +static const int EDGE_RECIPROCAL_UNDIRECTED = 2; Edge::Edge( GraphicsWidget *gw, Node *from, Node *to, - const Qt::PenStyle &style, const float &weight, - const int &nodeSize, + const QString &label, const QString &color, - const bool &reciprocal, + const Qt::PenStyle &style, + const int &type, const bool &drawArrows, - const bool &bez ) : graphicsWidget(gw) + const bool &bezier, + const bool &weightNumbers) : graphicsWidget(gw) { - qDebug("Edge: Edge()"); - Q_UNUSED(nodeSize); graphicsWidget->scene()->addItem(this); //add edge to scene to be displayed from->addOutLink( this ); //adds this Edge to sourceNode @@ -65,32 +68,56 @@ Edge::Edge( GraphicsWidget *gw, m_style = style; m_color=color; m_drawArrows=drawArrows; - m_reciprocal=reciprocal; + m_edgeType=type; + + m_directed_first = false; + m_startOffset=source->size(); //used to offset edge from the centre of node m_endOffset=target->size(); //used to offset edge from the centre of node - // qDebug("Edge() m_startOffset %i",(int) m_startOffset); - // qDebug("Edge() m_endOffset %i",(int) m_endOffset); - m_arrowSize=4; //controls the width of the edge arrow - eFrom = source->nodeNumber() ; eTo = target->nodeNumber() ; m_weight = weight ; - m_Bezier = bez; + m_Bezier = bezier; + + m_label = label; + m_drawLabel = !m_label.isEmpty(); + m_drawWeightNumber = weightNumbers; + + qDebug()<< "Edge::Edge(): " << eFrom << "->" << eTo + <<" = " << m_weight + <<" label " << m_label + <<" edgeType " << m_edgeType; + + if (m_drawWeightNumber) { + addWeightNumber(); + } + if (m_drawLabel) + addLabel(); + + setAcceptHoverEvents(true); +// setFlags(QGraphicsItem::ItemIsSelectable); + + //Edges have lower z than nodes. Nodes always appear above edges. + setZValue(253); + + setBoundingRegionGranularity(0); + //setCacheMode (QGraphicsItem::ItemCoordinateCache); + adjust(); } -void Edge::showArrows(bool drawArrows){ +void Edge::showArrows(const bool &drawArrows){ prepareGeometryChange(); m_drawArrows=drawArrows; + adjust(); } void Edge::removeRefs(){ - //FIXME Need to disconnect signals from node to this "erased" edge qDebug("Edge: removeRefs()"); source->deleteOutLink(this); target->deleteInLink(this); @@ -121,14 +148,15 @@ QString Edge::colorToPajek() { /** * @brief Called from MW when user wants to change an edge's weight. - Updates both the width and the EdgeWeight + Updates both the width and the weightNumber * @param w */ void Edge::setWeight(const float &w) { + qDebug() << "Edge::setWeight() " << w; + prepareGeometryChange(); m_weight = w; - foreach (EdgeWeight *wgt, weightList) ///update the edgeWeight of this edge as well. - wgt->setPlainText (QString::number(w)); - + if (m_drawWeightNumber) + weightNumber->setPlainText (QString::number(w)); } float Edge::weight() const { @@ -136,7 +164,78 @@ float Edge::weight() const { } -void Edge::setStartOffset(int offset){ + +void Edge::addWeightNumber (){ + // create edge weight item + double x = -20 + ( source->x() + target->x() ) / 2.0; + double y = -20 + ( source->y() + target->y() ) / 2.0; + weightNumber = new EdgeWeight (this, 7, QString::number(m_weight) ); + weightNumber-> setPos(x,y); + weightNumber-> setDefaultTextColor (m_color); + m_drawWeightNumber = true; +} + +void Edge::setWeightNumberVisibility (const bool &toggle) { + if (m_drawWeightNumber) { + if (toggle) + weightNumber ->show(); + else + weightNumber ->hide(); + } + else{ + if (toggle) + addWeightNumber(); + } + +} + + + + +/** + * @brief Called from MW when user wants to change an edge's label + + * @param label + */ +void Edge::setLabel(const QString &label) { + qDebug() << "Edge::setLabel() " << label; + prepareGeometryChange(); + m_label = label; + if (m_drawLabel) + edgeLabel->setPlainText (m_label); +} + +QString Edge::label() const { + return m_label; +} + + +void Edge::addLabel (){ + // create edge label item + double x = 5+ ( source->x() + target->x() ) / 2.0; + double y = 5+ ( source->y() + target->y() ) / 2.0; + edgeLabel = new EdgeLabel (this, 7, m_label ); + edgeLabel-> setPos(x,y); + edgeLabel-> setDefaultTextColor (m_color); + m_drawLabel = true; +} + +void Edge::setLabelVisibility (const bool &toggle) { + if (m_drawLabel) { + if (toggle) + edgeLabel ->show(); + else + edgeLabel ->hide(); + } + else{ + if (toggle) + addLabel(); + } + +} + + +void Edge::setStartOffset(const int &offset){ m_startOffset=offset; } @@ -175,46 +274,139 @@ int Edge::targetNodeNumber() { } -/** - * @brief Called from EdgeWeight objects to 'connect' them to this edge. - * @param canvasWeight - */ -void Edge::addWeight (EdgeWeight* canvasWeight ) { - weightList.push_back( canvasWeight) ; -} - - -void Edge::clearWeightList(){ - foreach (EdgeWeight *wgt, weightList) //Delete this weight - wgt->deleteLater(); - - weightList.clear(); -} - - /** * @brief Leaves some empty space (offset) from node - * make the edge weight appear on the centre of the edge */ void Edge::adjust(){ - // qDebug("Edge: adjust()"); + qDebug() << "Edge::adjust()"; if (!source || !target) return; - QLineF line(mapFromItem(source, 0, 0), mapFromItem(target, 0, 0)); + //QLineF line(mapFromItem(source, 0, 0), mapFromItem(target, 0, 0)); + QLineF line(source->x(), source->y(), target->x(), target->y()); QPointF edgeOffset; + line_length = line.length(); + line_dx = line.dx(); + line_dy = line.dy(); if (source!=target) { - qreal length = line.length(); - edgeOffset = QPointF((line.dx() * m_endOffset) / length, (line.dy() *m_endOffset) / length); + edgeOffset = QPointF( + (line_dx * m_endOffset) / line_length, + (line_dy * m_endOffset) / line_length); } else edgeOffset = QPointF(0, 0); prepareGeometryChange(); - sourcePoint = line.p1() + edgeOffset; - targetPoint = line.p2() - edgeOffset; - // qDebug()<<"----Edge: adjust() "<< sourcePoint.x()<< " "<setPos( (source->x()+target->x())/2.0, (source->y()+target->y())/2.0 ); + sourcePoint = line.p1() + edgeOffset ; + targetPoint = line.p2() - edgeOffset ; + + if (m_edgeType == EDGE_DIRECTED_OPPOSITE_EXISTS ) { + if (m_directed_first ) { + sourcePoint -= QPointF(4,4); + targetPoint -= QPointF(4,4); + } + else { + sourcePoint += QPointF(4,4); + targetPoint += QPointF(4,4); + + } + + } + if (m_drawWeightNumber) + weightNumber->setPos( + -20 + (source->x()+target->x())/2.0, + -20+ (source->y()+target->y())/2.0 ); + + if (m_drawLabel) + edgeLabel->setPos( + 5+ (source->x()+target->x())/2.0, + 5+ (source->y()+target->y())/2.0 ); + + //Define the path upon which we' ll draw the line + //QPainterPath line(sourcePoint); + m_path = new QPainterPath(sourcePoint); + + //Construct the path + if (source!=target) { + if ( !m_Bezier){ + // qDebug()<< "*** Edge::paint(). Constructing a line"; + m_path->lineTo(targetPoint); + } + else { + qDebug() << "*** Edge::paint(). Constructing a bezier curve"; + } + } + else { //self-link + QPointF c1 = QPointF( targetPoint.x() -30, targetPoint.y() -30 ); + QPointF c2 = QPointF( targetPoint.x() +30, targetPoint.y() -30 ); +// qDebug()<< "*** Edge::paint(). Constructing a bezier self curve c1 " +// <cubicTo( c1, c2, targetPoint); + } + + //Draw the arrows only if we have different nodes + //and the nodes are enough far apart from each other + if (m_drawArrows && source!=target && line_length > 10) { + angle = 0; +// line_length = m_path->length(); +// line_dx = targetPoint.x()-sourcePoint.x(); +// line_dy = targetPoint.y()-sourcePoint.y(); + if ( line_length > 0 ) + angle = ::acos( line_dx / line_length ); + // qDebug() << " acos() " << ::acos( line_dx / line_length ) ; + + if ( line_dy >= 0) + angle = TwoPi - angle; + + +// qDebug() << "*** Edge::paint(). Constructing arrows. " +// "First Arrow at target node" +// << "target-source: " << line_dx +// << " length: " << line_length +// << " angle: "<< angle; + + QPointF destArrowP1 = targetPoint + QPointF(sin(angle - Pi / 3) * m_arrowSize, + cos(angle - Pi / 3) * m_arrowSize); + QPointF destArrowP2 = targetPoint + QPointF(sin(angle - Pi + Pi / 3) * m_arrowSize, + cos(angle - Pi + Pi / 3) * m_arrowSize); +// qDebug() << "*** Edge::paint() destArrowP1 " +// << destArrowP1.x() << "," << destArrowP1.y() +// << " destArrowP2 " << destArrowP2.x() << "," << destArrowP2.y(); + + m_path->addPolygon ( QPolygonF() + << targetPoint + << destArrowP1 + << destArrowP2 + << targetPoint + ); + + if (m_edgeType == EDGE_RECIPROCAL_UNDIRECTED ) { + // qDebug() << "**** Edge::paint() This edge is SYMMETRIC! " + // << " So, we need to create Arrow at src node as well"; + QPointF srcArrowP1 = sourcePoint + QPointF(sin(angle +Pi / 3) * m_arrowSize, + cos(angle +Pi / 3) * m_arrowSize); + QPointF srcArrowP2 = sourcePoint + QPointF(sin(angle +Pi - Pi / 3) * m_arrowSize, + cos(angle +Pi - Pi / 3) * m_arrowSize); + + m_path->addPolygon ( QPolygonF() + << sourcePoint + << srcArrowP1 + << srcArrowP2 + <controlPointRect(); } - -void Edge::makeReciprocal(){ - qDebug("Edge::makeReciprocal()"); +void Edge::setDirectedWithOpposite(){ + qDebug()<< "Edge::setDirectedWithOpposite()"; prepareGeometryChange(); - m_reciprocal= true; + m_edgeType = EDGE_DIRECTED_OPPOSITE_EXISTS; + m_directed_first= true; } -void Edge::unmakeReciprocal(){ - qDebug("Edge::unmakeReciprocal()"); + +void Edge::setUndirected(){ + qDebug()<< "Edge::setUndirected()"; prepareGeometryChange(); - m_reciprocal= false; + m_edgeType = EDGE_RECIPROCAL_UNDIRECTED; + m_directed_first= false; + m_drawArrows = false; + adjust(); } -bool Edge::isReciprocal() { - return m_reciprocal; + +bool Edge::isUndirected() { + return ( m_edgeType == EDGE_RECIPROCAL_UNDIRECTED ) ? true:false; } @@ -304,7 +501,7 @@ Qt::PenStyle Edge::style() const{ QPen Edge::pen() const { if (m_weight < 0 ){ - return QPen(QColor("red"), width(), Qt::DashLine, Qt::RoundCap, Qt::RoundJoin); + return QPen(QColor(m_color), width(), Qt::DashLine, Qt::RoundCap, Qt::RoundJoin); } return QPen(QColor(m_color), width(), style(), Qt::RoundCap, Qt::RoundJoin); } @@ -314,94 +511,27 @@ QPen Edge::pen() const { void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *){ if (!source || !target) return; - Q_UNUSED(option); // painter->setClipRect( option->exposedRect ); - // qDebug() <<"@@@ Edge::paint()"; - - // qDebug()<x() <<","<< (sourceNode())->y() - // << ") to node "<x() - // <<","<< (targetNode())->y() << ") of weight "<< m_weight; - - //Define the path upon which we' ll draw the line - QPainterPath line(sourcePoint); - //Construct the path - if (source!=target) { - if ( !m_Bezier){ - // qDebug()<< "*** Edge::paint(). Constructing a line"; - line.lineTo(targetPoint); - } - else { - qDebug() << "*** Edge::paint(). Constructing a bezier curve"; - } - } - else { //self-link - QPointF c1 = QPointF( targetPoint.x() -30, targetPoint.y() -30 ); - QPointF c2 = QPointF( targetPoint.x() +30, targetPoint.y() -30 ); -// qDebug()<< "*** Edge::paint(). Constructing a bezier self curve c1 " -// <setPen( pen() ); - - //Draw the arrows only if we have different nodes. - if (m_drawArrows && source!=target) { - angle = 0; - line_length = line.length(); - line_dx = targetPoint.x()-sourcePoint.x(); - line_dy = targetPoint.y()-sourcePoint.y(); - if ( line.length() >0 ) - angle = ::acos( line_dx / line_length ); - // qDebug() << " acos() " << ::acos( line_dx / line_length ) ; - - if ( line_dy >= 0) - angle = TwoPi - angle; - - // qDebug() << "*** Edge::paint(). Constructing arrows. First Arrow at target node" - // << "target-source: " << line_dx - // << " length: " << line_length - // << " angle: "<< angle; - - QPointF destArrowP1 = targetPoint + QPointF(sin(angle - Pi / 3) * m_arrowSize, - cos(angle - Pi / 3) * m_arrowSize); - QPointF destArrowP2 = targetPoint + QPointF(sin(angle - Pi + Pi / 3) * m_arrowSize, - cos(angle - Pi + Pi / 3) * m_arrowSize); - // qDebug() << "*** Edge::paint() destArrowP1 " - // << destArrowP1.x() << "," << destArrowP1.y() - // << " destArrowP2 " << destArrowP2.x() << "," << destArrowP2.y(); - painter->setBrush(QColor(m_color)); - QPolygonF destP; - destP << targetPoint << destArrowP1 << destArrowP2; - line.addPolygon ( destP); - //painter->drawPolygon(QPolygonF() << line.p2() << destArrowP1 << destArrowP2); - if (m_reciprocal) { -// qDebug() << "**** Edge::paint() This edge is SYMMETRIC! " -// << " So, we need to create Arrow at src node as well"; - QPointF srcArrowP1 = sourcePoint + QPointF(sin(angle +Pi / 3) * m_arrowSize, - cos(angle +Pi / 3) * m_arrowSize); - QPointF srcArrowP2 = sourcePoint + QPointF(sin(angle +Pi - Pi / 3) * m_arrowSize, - cos(angle +Pi - Pi / 3) * m_arrowSize); - // qDebug() << "*** Edge::paint() srcArrowP1 " << srcArrowP1.x() << "," << srcArrowP1.y() - // << " srcArrowP2 " << srcArrowP2.x() << "," << srcArrowP2.y(); - QPolygonF srcP; - srcP << sourcePoint<< srcArrowP1<< srcArrowP2; - line.addPolygon ( srcP); - - // painter->drawPolygon(QPolygonF() << line.p1() << srcArrowP1 << srcArrowP2); - } - else { - // qDebug() << "*** Edge::paint() Not symmetric edge. Finish"; - } - } - else { -// qDebug()<< "*** Edge::paint(). This edge is self-link - CONTINUE!"; - } - // qDebug()<< "### Edge::paint(). DrawPath now...."; - painter->drawPath(line); + // painter->setBrush(QColor(m_color)); + + //if the edge is being dragged around, darken it! + if (option->state & QStyle::State_Selected) { + painter->setPen( + QPen(QColor("m_red"), width(), style(), Qt::RoundCap, Qt::RoundJoin) + ); + } + else if (option->state & QStyle::State_MouseOver) { + painter->setPen( + QPen(QColor("red"), width()+5, style(), Qt::RoundCap, Qt::RoundJoin) + ); + setZValue(255); + } + setZValue(253); + + painter->drawPath(*m_path); } @@ -409,7 +539,7 @@ void Edge::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid Controls the width of the edge; is a function of edge weight */ float Edge::width() const{ - // qDebug()<< "Edge::width() will return "<< fabs(m_weight); + qDebug()<< "Edge::width() will return "<< fabs(m_weight); if ( fabs(m_weight) > 1 ) return 1 + fabs(m_weight)/10; return 1; // Default, if m_weight in (-1, 1) space @@ -417,6 +547,20 @@ float Edge::width() const{ +/** + * @brief Edge::highlight + * @param flag + */ +void Edge::highlight(const bool &flag) { + qDebug()<< "Edge::highlight() - " << flag; + if (flag) { + m_tempColor = m_color; + m_tempweight = m_weight; + setColor("red"); + } + else setColor(m_tempColor); +} + /** handles the events of a click on an edge*/ void Edge::mousePressEvent(QGraphicsSceneMouseEvent *event) { @@ -436,10 +580,15 @@ void Edge::mousePressEvent(QGraphicsSceneMouseEvent *event) { Edge::~Edge(){ - qDebug() << "\n\n\n *** ~EDGE() " << sourceNodeNumber()<< "->" << targetNodeNumber(); + qDebug() << "*** ~Edge() - edge " << sourceNodeNumber()<< "->" << targetNodeNumber(); removeRefs(); - weightList.clear(); - this->hide(); + if (m_drawWeightNumber) + graphicsWidget->removeItem(weightNumber); + if (m_drawLabel) + graphicsWidget->removeItem(edgeLabel); + + this->hide(); + graphicsWidget->removeItem(this); } diff --git a/src/edge.h b/src/edge.h index dc915378..f1807640 100755 --- a/src/edge.h +++ b/src/edge.h @@ -1,11 +1,11 @@ /*************************************************************************** - SocNetV: Social Network Visualizer + SocNetV: Social Network Visualizer version: 2.0 Written in Qt edge.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -38,47 +38,58 @@ class GraphicsWidget; class QGraphicsSceneMouseEvent; class Node; class EdgeWeight; +class EdgeLabel; + + static const int TypeEdge= QGraphicsItem::UserType+2; class Edge : public QObject, public QGraphicsItem { - Q_OBJECT - Q_INTERFACES (QGraphicsItem) + Q_OBJECT + Q_INTERFACES (QGraphicsItem) public: - Edge(GraphicsWidget *, Node*, Node*, + Edge(GraphicsWidget *, Node*, Node*, const float &weight, + const QString &label, const QString &color, const Qt::PenStyle &style, - const float &, const int &, const QString &, - const bool&, const bool&, const bool &); + const int&type, const bool & drawArrows, const bool &bezier, + const bool &weightNumbers=false); ~Edge(); - enum { Type = UserType + 2 }; - int type() const { return Type; } - Node *sourceNode() const; - void setSourceNode(Node *node); - - Node *targetNode() const; - void setTargetNode(Node *node); - - void setStartOffset(int ); - void setEndOffset(int ); - void removeRefs(); - - int sourceNodeNumber(); - int targetNodeNumber(); - void setWeight( const float &w) ; + enum { Type = UserType + 2 }; + int type() const { return Type; } + Node *sourceNode() const; + void setSourceNode(Node *node); + + Node *targetNode() const; + void setTargetNode(Node *node); + + void setStartOffset(const int & ); + void setEndOffset(int ); + void removeRefs(); + int sourceNodeNumber(); + int targetNodeNumber(); + + void setWeight( const float &w) ; float weight() const; - void addWeight (EdgeWeight* canvasWeight ) ; - void clearWeightList(); + void addWeightNumber (); + //void deleteWeightNumber(); + void setWeightNumberVisibility (const bool &toggle); - void showArrows(bool); + void setLabel( const QString &label) ; + QString label() const; + void addLabel(); + //void deleteLabel(); + void setLabelVisibility (const bool &toggle); + + void showArrows(const bool &); void toggleAntialiasing(bool); - void makeReciprocal(); - void unmakeReciprocal(); - bool isReciprocal(); + void setUndirected(); + bool isUndirected(); + void setDirectedWithOpposite(); float width() const; @@ -90,31 +101,38 @@ class Edge : public QObject, public QGraphicsItem { QString color() const ; QString colorToPajek(); - QPainterPath shape() const; + void highlight (const bool &flag); + + QPainterPath shape() const; public slots: - void adjust (); + void adjust (); protected: - QRectF boundingRect() const; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - void mousePressEvent(QGraphicsSceneMouseEvent *event); + QRectF boundingRect() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + void mousePressEvent(QGraphicsSceneMouseEvent *event); private: - GraphicsWidget *graphicsWidget; - Node *source, *target; - QPointF sourcePoint, targetPoint; - qreal m_arrowSize, m_startOffset, m_endOffset; + GraphicsWidget *graphicsWidget; + Node *source, *target; + QPainterPath *m_path; + QPointF sourcePoint, targetPoint; + qreal m_arrowSize, m_startOffset, m_endOffset; Qt::PenStyle m_style; - list weightList; - QString m_color; - int eFrom, eTo; - float m_weight; - int tox1, tox2, toy1, toy2, size; - double rad, theta, theta1, theta2; - qreal angle, line_length, line_dx, line_dy; - bool m_Bezier, m_drawArrows, m_reciprocal; + EdgeWeight* weightNumber; + EdgeLabel* edgeLabel; + + QString m_color, m_tempColor, m_colorNegative, m_label; + int eFrom, eTo; + float m_weight, m_tempweight; + int tox1, tox2, toy1, toy2, size; + int m_edgeType; + double rad, theta, theta1, theta2; + qreal angle, line_length, line_dx, line_dy; + bool m_Bezier, m_drawArrows, m_directed_first, m_drawWeightNumber; + bool m_drawLabel; }; #endif diff --git a/src/edgelabel.cpp b/src/edgelabel.cpp new file mode 100755 index 00000000..349d8db9 --- /dev/null +++ b/src/edgelabel.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + SocNetV: Social Network Visualizer + version: 2.0 + Written in Qt + + edgelabel.cpp - description + ------------------- + copyright : (C) 2005-2016 by Dimitris B. Kalamaras + email : dimitris.kalamaras@gmail.com + ***************************************************************************/ + +/******************************************************************************* +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 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 . * +********************************************************************************/ + +#include "edgelabel.h" +#include "edge.h" +#include +#include + + +EdgeLabel::EdgeLabel( Edge *link , int size, QString labelText) +: QGraphicsTextItem( 0) +{ + qDebug()<< "EdgeLabel:: creating new edgelabel and attaching it to link"; + setPlainText( labelText ); + setParentItem(link); //auto disables child items like this, when link is disabled. + this->setFont( QFont ("Courier", size, QFont::Light, true) ); + setZValue(253); +} + +void EdgeLabel::move(double x, double y) { + move(x,y); +} + +EdgeLabel::~EdgeLabel() +{ +} + + diff --git a/src/edgelabel.h b/src/edgelabel.h new file mode 100755 index 00000000..ea08ef61 --- /dev/null +++ b/src/edgelabel.h @@ -0,0 +1,51 @@ +/*************************************************************************** + SocNetV: Social Network Visualizer + version: 2.0 + Written in Qt + edgelabel.h - description + ------------------- + copyright : (C) 2005-2016 by Dimitris B. Kalamaras + email : dimitris.kalamaras@gmail.com + ***************************************************************************/ + +/******************************************************************************* +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 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 . * +********************************************************************************/ + + + +#ifndef EDGELABEL_H +#define EDGELABEL_H + + +#include +class Edge; + +static const int TypeEdgeLabel = QGraphicsItem::UserType+6; + +class EdgeLabel: public QGraphicsTextItem +{ +public: + EdgeLabel(Edge * , int, QString); + void removeRefs(); + void move(double x, double y); + + enum { Type = UserType + 6 }; + int type() const { return Type; } + + ~EdgeLabel(); +private: +}; + +#endif diff --git a/src/edgeweight.cpp b/src/edgeweight.cpp index 2036918b..1b6476a1 100755 --- a/src/edgeweight.cpp +++ b/src/edgeweight.cpp @@ -5,7 +5,7 @@ edgeweight.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -34,7 +34,6 @@ EdgeWeight::EdgeWeight( Edge *link , int size, QString labelText) : QGraphicsTextItem( 0) { qDebug()<< "EdgeWeight:: creating new edgeweight and attaching it to link"; - link -> addWeight(this); setPlainText( labelText ); setParentItem(link); //auto disables child items like this, when link is disabled. this->setFont( QFont ("Courier", size, QFont::Light, true) ); diff --git a/src/edgeweight.h b/src/edgeweight.h index 899b3e5a..c8036941 100755 --- a/src/edgeweight.h +++ b/src/edgeweight.h @@ -4,7 +4,7 @@ Written in Qt edgeweight.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ diff --git a/src/filteredgesbyweightdialog.cpp b/src/filteredgesbyweightdialog.cpp index eb5bfdc2..ad53d544 100755 --- a/src/filteredgesbyweightdialog.cpp +++ b/src/filteredgesbyweightdialog.cpp @@ -5,7 +5,7 @@ filteredgesbyweightdialog.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ diff --git a/src/filteredgesbyweightdialog.h b/src/filteredgesbyweightdialog.h index c6dbfe67..ef669ce9 100755 --- a/src/filteredgesbyweightdialog.h +++ b/src/filteredgesbyweightdialog.h @@ -5,7 +5,7 @@ filteredgesbyweightdialog.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ diff --git a/src/forms/datasetselectdialog.ui b/src/forms/datasetselectdialog.ui index ad419aa5..9474f3c8 100644 --- a/src/forms/datasetselectdialog.ui +++ b/src/forms/datasetselectdialog.ui @@ -9,20 +9,26 @@ 0 0 - 422 - 160 + 490 + 170 + + + 0 + 0 + + - 400 - 160 + 460 + 170 - 600 - 195 + 490 + 185 @@ -33,7 +39,7 @@ Select Data Set - + @@ -67,32 +73,31 @@ - + 0 0 - 350 - 40 + 400 + 60 0 - 110 + 100 - DejaVu Sans - 11 + Sans Serif + 10 - SocNetV is able to automatically create known data sets, such as Padgett's florentine families etc. -Select the data set you want to re-create from the list: + <html><head/><body><p>SocNetV can automatically recreate and visualize known data sets, such as Padgett's florentine families, Zachary's Karate Club etc.</p><p>Select the data set you want to re-create from the list.</p></body></html> Qt::RichText @@ -102,19 +107,6 @@ Select the data set you want to re-create from the list: - - - - - DejaVu Sans - 11 - - - - Select - - - @@ -128,8 +120,8 @@ Select the data set you want to re-create from the list: - DejaVu Sans - 10 + Sans Serif + 9 @@ -144,8 +136,7 @@ Select the data set you want to re-create from the list: - DejaVu Sans - 11 + 10 @@ -156,6 +147,19 @@ Select the data set you want to re-create from the list: + + + + + Sans Serif + 10 + + + + Select + + + diff --git a/src/forms/filteredgesbyweightdialog.ui b/src/forms/filteredgesbyweightdialog.ui index dd209459..6fe7ef20 100644 --- a/src/forms/filteredgesbyweightdialog.ui +++ b/src/forms/filteredgesbyweightdialog.ui @@ -18,7 +18,7 @@ - DejaVu Sans + 10 @@ -29,8 +29,7 @@ - DejaVu Sans - 11 + Sans Serif @@ -62,8 +61,7 @@ - DejaVu Sans - 11 + Sans Serif @@ -75,8 +73,8 @@ - DejaVu Sans - 11 + Sans Serif + 10 @@ -93,8 +91,7 @@ - DejaVu Sans - 11 + Sans Serif @@ -106,8 +103,7 @@ - DejaVu Sans - 11 + Sans Serif @@ -117,12 +113,6 @@ - - - DejaVu Sans - 11 - - Qt::Horizontal diff --git a/src/forms/nodeeditdialog.ui b/src/forms/nodeeditdialog.ui index 09492575..94e4dbfe 100644 --- a/src/forms/nodeeditdialog.ui +++ b/src/forms/nodeeditdialog.ui @@ -32,14 +32,14 @@ Node Properties - + - DejaVu Sans - 11 + Sans Serif + 10 @@ -49,17 +49,66 @@ + + + Sans Serif + 10 + + + + + + + + + + + + + Sans Serif + 10 + + + + Node size (default 8) + + + + + DejaVu Sans 11 + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + Sans Serif + 10 + + + + 8 + - + @@ -68,8 +117,8 @@ - DejaVu Sans - 11 + Sans Serif + 10 @@ -103,31 +152,31 @@ - DejaVu Sans - 11 + Sans Serif + 10 - - + + - + - DejaVu Sans - 11 + Sans Serif + 10 - Node shape + Node color (click the button to select) - + DejaVu Sans @@ -146,7 +195,13 @@ - + + + + 60 + 25 + + DejaVu Sans @@ -154,50 +209,54 @@ - + ... - - - :/images/box.png:/images/box.png + + + 60 + 20 + + + + + - + - DejaVu Sans - 11 + Sans Serif + 10 - - - - - :/images/circle.png:/images/circle.png + Node shape - + DejaVu Sans 11 - - + + Qt::Horizontal - - - :/images/diamond.png:/images/diamond.png + + + 40 + 20 + - + - + DejaVu Sans @@ -209,12 +268,12 @@ - :/images/ellipse.png:/images/ellipse.png + :/images/box.png:/images/box.png - + DejaVu Sans @@ -226,32 +285,12 @@ - :/images/triangle.png:/images/triangle.png + :/images/circle.png:/images/circle.png - - - - - - - DejaVu Sans - 11 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - + DejaVu Sans @@ -259,37 +298,16 @@ - Node color (click the button to select) - - - - - - - - DejaVu Sans - 11 - - - - Qt::Horizontal + - - - 40 - 20 - + + + :/images/diamond.png:/images/diamond.png - + - - - - 60 - 25 - - + DejaVu Sans @@ -297,22 +315,16 @@ - ... + - - - 60 - 20 - + + + :/images/ellipse.png:/images/ellipse.png - - - - - + DejaVu Sans @@ -320,44 +332,52 @@ - Node size (default 8) + + + + + :/images/triangle.png:/images/triangle.png - + DejaVu Sans 11 - - Qt::Horizontal - - - - 40 - 20 - + + <html><head/><body><p><span style=" font-weight:600;">Node shape: Triangle</span></p><p>Change all node shapes to &quot;triangle&quot;.</p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the &quot;triangle&quot; shape will be saved and it will be used in all future SocNetV sessions to create new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> - - - - - - - DejaVu Sans - 11 - + + - - 8 + + + :/images/star.png:/images/star.png + + + + + Sans Serif + 9 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + diff --git a/src/forms/randerdosrenyidialog.ui b/src/forms/randerdosrenyidialog.ui index 249ffebc..06caa8fb 100644 --- a/src/forms/randerdosrenyidialog.ui +++ b/src/forms/randerdosrenyidialog.ui @@ -6,38 +6,38 @@ 0 0 - 610 - 371 + 560 + 520 - + 0 0 - 610 - 365 + 560 + 520 650 - 400 + 539 - DejaVu Sans + 10 ErdÅ‘s–Rényi network generator - - + + @@ -47,16 +47,19 @@ - 560 - 50 + 540 + 85 + + + + + 16777215 + 96 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -66,10 +69,7 @@ QFrame::Sunken - Generate random network according to ErdÅ‘s–Rényi (ER) model. -In fact, there are two models: in G(n,p) edges are created with Bernoulli trials, -while in G(n,M) a graph is randomly selected from all graphs with - n nodes and M edges + <html><head/><body><p>Generate random network according to ErdÅ‘s–Rényi (ER) model. </p><p>In fact, there are two models: in <span style=" font-style:italic;">G(n,p)</span> edges are created with Bernoulli trials, while in <span style=" font-style:italic;">G(n,M) </span>a graph is randomly selected from all graphs with <span style=" font-style:italic;">n</span> nodes and <span style=" font-style:italic;">M</span> edges. Read more in the manual.</p></body></html> Qt::RichText @@ -79,7 +79,14 @@ while in G(n,M) a graph is randomly selected from all graphs with - + + + + Qt::Horizontal + + + + @@ -91,16 +98,13 @@ while in G(n,M) a graph is randomly selected from all graphs with - 380 + 350 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -118,16 +122,13 @@ while in G(n,M) a graph is randomly selected from all graphs with - 100 + 120 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -143,7 +144,14 @@ while in G(n,M) a graph is randomly selected from all graphs with - + + + + Qt::Horizontal + + + + @@ -155,16 +163,13 @@ while in G(n,M) a graph is randomly selected from all graphs with - 380 + 350 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -178,16 +183,13 @@ while in G(n,M) a graph is randomly selected from all graphs with - 100 + 120 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -226,10 +228,7 @@ p, li { white-space: pre-wrap; } - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -238,6 +237,9 @@ p, li { white-space: pre-wrap; } G(n, M) + + false + false @@ -247,7 +249,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + QLayout::SetMinimumSize @@ -262,16 +271,13 @@ p, li { white-space: pre-wrap; } - 380 + 350 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -283,16 +289,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -305,7 +308,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + @@ -317,16 +327,13 @@ p, li { white-space: pre-wrap; } - 380 + 350 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -344,16 +351,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -372,7 +376,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + @@ -384,16 +395,13 @@ p, li { white-space: pre-wrap; } - 380 + 350 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -413,26 +421,20 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - DejaVu Sans - 11 - 50 - false - false - false - false + Sans Serif Undirected - true + false false @@ -449,21 +451,21 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - DejaVu Sans - 11 - 50 - false + Sans Serif Directed + + false + false @@ -473,7 +475,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + @@ -485,16 +494,13 @@ p, li { white-space: pre-wrap; } - 380 + 350 0 - DejaVu Sans - 11 - 50 - false + Sans Serif @@ -514,23 +520,20 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - DejaVu Sans - 11 - 50 - false + Sans Serif Yes, allow - true + false @@ -538,12 +541,19 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + - DejaVu Sans - 11 + Sans Serif + 10 50 false diff --git a/src/forms/randscalefreedialog.ui b/src/forms/randscalefreedialog.ui index fd136f0c..dc1edcee 100644 --- a/src/forms/randscalefreedialog.ui +++ b/src/forms/randscalefreedialog.ui @@ -6,41 +6,41 @@ 0 0 - 528 - 427 + 580 + 530 - + 0 0 - 528 - 350 + 580 + 530 - 550 - 450 + 600 + 580 - DejaVu Sans + 10 Scale-free random network generator - - + + - + 0 0 @@ -48,16 +48,18 @@ 450 - 50 + 100 + + + + + 16777215 + 110 - 11 - 50 - false - false - false + Sans Serif @@ -67,7 +69,7 @@ QFrame::Sunken - <html><head/><body><p>Generate a random scale-free network of <span style=" font-style:italic;">n</span> nodes according to the Barabási–Albert (BA) model which uses a preferential attachment mechanism. The model starts with <span style=" font-style:italic;">m</span><span style=" font-style:italic; vertical-align:sub;">0</span> connected nodes. In each step a new node is added, along with <span style=" font-style:italic;">m</span> edges to existing nodes. Read more in the manual.</p></body></html> + <html><head/><body><p>Generate a random scale-free network of <span style=" font-style:italic;">n</span> nodes according to the Barabási–Albert (BA) model which uses a preferential attachment mechanism. </p><p>The model starts with <span style=" font-style:italic;">m</span><span style=" font-style:italic; vertical-align:sub;">0</span> connected nodes. In each step a new node is added, along with <span style=" font-style:italic;">m</span> edges to existing nodes. Read more in the manual.</p></body></html> Qt::RichText @@ -77,7 +79,14 @@ - + + + + Qt::Horizontal + + + + @@ -95,7 +104,7 @@ - 11 + Sans Serif @@ -113,13 +122,13 @@ - 100 + 120 0 - 11 + Sans Serif @@ -138,7 +147,14 @@ - + + + + Qt::Horizontal + + + + QLayout::SetMinimumSize @@ -159,15 +175,11 @@ - 11 + Sans Serif - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Power of preferential attachment <span style=" font-style:italic;">p </span></p></body></html> + <html><head/><body><p>Power of preferential attachment <span style=" font-style:italic;">p</span></p></body></html> @@ -175,13 +187,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - 11 + Sans Serif @@ -203,7 +215,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + QLayout::SetMinimumSize @@ -224,15 +243,11 @@ p, li { white-space: pre-wrap; } - 11 + Sans Serif - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Initial connected nodes <span style=" font-style:italic;">m</span><span style=" font-style:italic; vertical-align:sub;">0</span></p></body></html> + <html><head/><body><p>Initial connected nodes <span style=" font-style:italic;">m</span><span style=" font-style:italic; vertical-align:sub;">0</span></p></body></html> @@ -240,13 +255,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - 11 + Sans Serif @@ -268,7 +283,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + QLayout::SetMinimumSize @@ -289,15 +311,11 @@ p, li { white-space: pre-wrap; } - 11 + Sans Serif - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Edges to add in each step <span style=" font-style:italic;">m</span></p></body></html> + <html><head/><body><p>Edges to add in each step <span style=" font-style:italic;">m</span></p></body></html> @@ -305,13 +323,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - 11 + Sans Serif @@ -333,7 +351,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + QLayout::SetMinimumSize @@ -354,15 +379,11 @@ p, li { white-space: pre-wrap; } - 11 + Sans Serif - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:11pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Zero appeal <span style=" font-style:italic;">α</span></p></body></html> + <html><head/><body><p>Zero appeal <span style=" font-style:italic;">α</span></p></body></html> @@ -370,13 +391,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - 11 + Sans Serif @@ -398,7 +419,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + @@ -416,9 +444,7 @@ p, li { white-space: pre-wrap; } - 11 - 50 - false + Sans Serif @@ -438,16 +464,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - 11 - false - false - false + Sans Serif @@ -471,13 +494,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - 11 + Sans Serif @@ -492,7 +515,14 @@ p, li { white-space: pre-wrap; } - + + + + Qt::Horizontal + + + + @@ -504,13 +534,13 @@ p, li { white-space: pre-wrap; } - 400 + 440 0 - 11 + Sans Serif @@ -530,13 +560,13 @@ p, li { white-space: pre-wrap; } - 100 + 120 0 - 11 + Sans Serif @@ -554,11 +584,11 @@ p, li { white-space: pre-wrap; } - + - 11 + 10 diff --git a/src/forms/randsmallworlddialog.ui b/src/forms/randsmallworlddialog.ui index 70a5cfab..aecffcec 100644 --- a/src/forms/randsmallworlddialog.ui +++ b/src/forms/randsmallworlddialog.ui @@ -6,31 +6,31 @@ 0 0 - 528 - 330 + 570 + 420 - + 0 0 - 500 - 330 + 570 + 400 - 550 - 350 + 580 + 420 - DejaVu Sans + 10 @@ -40,7 +40,7 @@ - + 0 0 @@ -48,16 +48,18 @@ 450 - 50 + 70 + + + + + 16777215 + 75 - 11 - 50 - false - false - false + Sans Serif @@ -67,10 +69,7 @@ QFrame::Sunken - Generate random network according to the Watts & Strogatz model. - This model produces graphs with small-world properties, including - short average path lengths and high clustering. - + <html><head/><body><p>Generate random network according to the <span style=" font-style:italic;">Watts &amp; Strogatz</span> model.</p><p>This model produces graphs with small-world properties, including short average path lengths and high clustering. Read more in the manual.</p></body></html> Qt::RichText @@ -81,6 +80,13 @@ + + + Qt::Horizontal + + + + @@ -98,7 +104,7 @@ - 11 + Sans Serif @@ -116,13 +122,13 @@ - 100 + 110 0 - 11 + Sans Serif @@ -141,7 +147,14 @@ - + + + + Qt::Horizontal + + + + QLayout::SetMinimumSize @@ -162,7 +175,7 @@ - 11 + Sans Serif @@ -174,13 +187,13 @@ - 100 + 110 0 - 11 + Sans Serif @@ -202,7 +215,14 @@ - + + + + Qt::Horizontal + + + + @@ -220,7 +240,7 @@ - 11 + Sans Serif @@ -238,13 +258,13 @@ - 100 + 110 0 - 11 + Sans Serif @@ -257,13 +277,20 @@ 0.010000000000000 - 0.500000000000000 + 0.300000000000000 - + + + + Qt::Horizontal + + + + @@ -281,9 +308,7 @@ - 11 - 50 - false + Sans Serif @@ -303,16 +328,13 @@ - 100 + 110 0 - 11 - false - false - false + Sans Serif @@ -342,7 +364,7 @@ - 11 + Sans Serif @@ -357,7 +379,14 @@ - + + + + Qt::Horizontal + + + + @@ -375,7 +404,7 @@ - 11 + Sans Serif @@ -395,13 +424,13 @@ - 100 + 110 0 - 11 + Sans Serif @@ -419,11 +448,20 @@ - + + + + Qt::Horizontal + + + + - 11 + Sans Serif + 10 + PreferDefault diff --git a/src/forms/settingsdialog.ui b/src/forms/settingsdialog.ui new file mode 100644 index 00000000..825165cd --- /dev/null +++ b/src/forms/settingsdialog.ui @@ -0,0 +1,1638 @@ + + + SettingsDialog + + + + 0 + 0 + 469 + 613 + + + + Settings & Preferences + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + 0 + + + + General + + + + + + Data Export + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Default Save / Export folder </span></p><p>Click the small button on the far right corner to select a folder, where all SocNetV files and reports will be saved by default. </p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p></body></html> + + + Save folder + + + + + + + Qt::Horizontal + + + + 48 + 20 + + + + + + + + + 220 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Default Save / Export folder </span></p><p>This is the path of the folder where all SocNetV files and reports will be saved. </p><p>Click the button on the right to select a new folder. </p><p>If the folder does not exist, it wil be created.</p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Default Save / Export folder </span></p><p>This is the path of the folder where all SocNetV files and reports will be saved. </p><p>Click the button on the right to select a new folder. </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. If the folder does not exist, it wil be created.</p></body></html> + + + + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Default Save / Export folder </span></p><p>Click this button to select a folder, where all SocNetV files and reports will be saved by default. </p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Default Save / Export folder </span></p><p>Click this button to select a folder, where all SocNetV files and reports will be saved by default. </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. If the folder does not exist, it wil be created.</p></body></html> + + + ... + + + + + + + + + + + + Debugging and Progressing + + + + + + <html><head/><body><p><span style=" font-weight:600;">Debug Messages</span></p><p>Enable or disable debug messages to strerr. </p><p>Once you enable this and press OK, you must close and run SocNetV again from the command line / terminal, in order to see the debug messages.</p><p>Enabling has a significant cpu cost but lets you know what SocNetV is actually doing.</p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Debug Messages</span></p><p>Enables or disable debug messages to strerr. </p><p>Enabling has a significant cpu cost but lets you know what SocNetV is actually doing.</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + Qt::LeftToRight + + + Print debug messages to command line + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Progress Bars</span></p><p>Enable or disable the application Progress Bars.</p><p>Progress Bars may appear during time-cost operations. </p><p>Enabling Progress Bars has a significant cpu cost but lets you know about the progress of a given operation.</p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Progress Bars</span></p><p>Enable or disable the application Progress Bars.</p><p>Progress Bars may appear during time-cost operations. </p><p>Enabling Progress Bars has a significant cpu cost but lets you know about the progress of a given operation.</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + Qt::LeftToRight + + + Show progress bars + + + true + + + + + + + + + + Canvas options + + + + + + + + Background color + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Background color</span></p><p>Click this button to select a new background color. </p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Background color</span></p><p>Click this button to select a new background color. </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + Background Image + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 200 + 0 + + + + <html><head/><body><p><span style=" font-weight:600;">Background image</span></p><p>This is the path of the default background image. </p><p>Click the button on the right to select a new background image.</p><p>If the file does not exist, the default background color will be used.</p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p><p><br/></p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Background image</span></p><p>This is the path of the default background image. </p><p>Click the button on the right to select a new background image.</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. If the file does not exist, the default background color will be used.</p></body></html> + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Background image</span></p><p>Click this button to select a new background image.</p><p>If the file does not exist, the default background color will be used.</p><p>This is a permanent setting. Once you press OK, it will be saved and will be the default of the application every time you run SocNetV - until you change it again.</p><p><br/></p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Background image</span></p><p>Click this button to select a new background image.</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. If the file does not exist, the default background color will be used.</p></body></html> + + + ... + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Anti-Aliasing</span></p><p>Enable or disable Anti-Aliasing.</p><p>Anti-aliasing is a technique which makes nodes, lines and text, smoother and fancier. But it comes at the cost of speed... </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p><p><br/></p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Anti-Aliasing</span></p><p>Enable or disable Anti-Aliasing.</p><p>Anti-aliasing is a technique which makes nodes, lines and text, smoother and fancier. But it comes at the cost of speed... </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p><p><br/></p></body></html> + + + Qt::LeftToRight + + + Enable antialiasing + + + + + + + <html><head/><body><p><span style=" font-weight:600;">SocNetV logo on exported images</span></p><p>Enable or disable the printing of a small SocNetV logo on exported PNG and BMP network images </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">SocNetV logo on exported images</span></p><p>Enable or disable the printing of a small SocNetV logo on exported PNG and BMP network images </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + Qt::LeftToRight + + + Print SocNetV logo on exported Images + + + true + + + + + + + + + + Window options + + + + + + <html><head/><body><p><span style=" font-weight:600;">Control panel</span></p><p>Enable or disable the Control panel (left panel)</p><p>The Control Panel is the widget at the left of the application window, where you can find essential functions and options for Editing, Analyzing and Visualizing your network data.</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Control panel</span></p><p>Enable or disable the Control panel (left panel)</p><p>The Control Panel is the widget at the left of the application window, where you can find essential functions and options for Editing, Analyzing and Visualizing your network data.</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + Qt::LeftToRight + + + Show Control panel (left panel) + + + true + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Statistics panel</span></p><p>Enable or disable the statistics panel (right panel)</p><p>The Statistics panel is the widget at the right of the application window, where you can see statistics about the whole network such as node and edge/arc count, density etc as well as statistics about the last clicked node (in-degree, out-degree, clustering coefficient etc).</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Statistics panel</span></p><p>Enable or disable the statistics panel (right panel)</p><p>The Statistics panel is the widget at the right of the application window, where you can see statistics about the whole network such as node and edge/arc count, density etc as well as statistics about the last clicked node (in-degree, out-degree, clustering coefficient etc).</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + Qt::LeftToRight + + + Show Statistics panel (right panel) + + + true + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Toolbar</span></p><p>Enable or disable the application toolbar.</p><p>The toolbar is the widget right below the menu, and carries useful icons. You can disable it if you like from here...</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Toolbar</span></p><p>Enable or disable the application toolbar.</p><p>The toolbar is the widget right below the menu, and carries useful icons. You can disable it if you like from here...</p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + Qt::LeftToRight + + + Show toolbar + + + true + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Statusbar</span></p><p>Enable or disable the application statusbar.</p><p>The statusbar is the widget at the bottom of the window, where messages appear. </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Statusbar</span></p><p>Enable or disable the application statusbar.</p><p>The statusbar is the widget at the bottom of the window, where messages appear. </p><p>This is a permanent setting, it will be the default of the application every time you run SocNetV. </p></body></html> + + + Qt::LeftToRight + + + Show statusbar + + + true + + + + + + + + + + + Nodes + + + + + + <html><head/><body><p><span style=" font-weight:600;">Default node settings</span></p><p>Any change to these settings will apply to all existing nodes immediately.</p><p>Once you press OK, these settings will be saved and they will be used in all future SocNetV sessions.</p></body></html> + + + Node settings + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node color</span></p><p>Click the colored button to select a new color for all nodes.</p><p>Any change to this setting will apply to all existing nodes immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node color when creating new nodes (except when loading network files which declare specific node settings).</p></body></html> + + + Node color + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Node color</span></p><p>Click this button to select a new node color for all nodes.</p><p>Any change to this setting will apply to all existing nodes immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node color when creating new nodes (except when loading network files which declare specific node settings).</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Node color</span></p><p>Click to select a new default node color.</p><p>Any change to this setting will apply to all existing nodes immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node color.</p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node shape</span></p><p>Click on any of the following shapes to select a new node shape for all nodes. </p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the default node shape will be saved and it will be used in all future SocNetV sessions when creating new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> + + + Node shape + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + <html><head/><body><p><span style=" font-weight:600;">Node shape: Square</span></p><p>Change all node shapes to &quot;square&quot; or &quot;box&quot;.</p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the &quot;box&quot; shape will be saved and it will be used in all future SocNetV sessions to create new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Default node shape</span></p><p>Click on any shape to select a new node shape for all nodes. This will apply to all existing nodes immediately.</p><p>Once you press OK, the default node shape will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + + + + + :/images/box.png:/images/box.png + + + + + + + + DejaVu Sans + 11 + + + + <html><head/><body><p><span style=" font-weight:600;">Node shape: Circle</span></p><p>Change all node shapes to &quot;circle&quot;.</p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the &quot;circle&quot; shape will be saved and it will be used in all future SocNetV sessions to create new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> + + + + + + + :/images/circle.png:/images/circle.png + + + + + + + + DejaVu Sans + 11 + + + + <html><head/><body><p><span style=" font-weight:600;">Node shape: Diamond</span></p><p>Change all node shapes to &quot;diamond&quot;.</p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the &quot;diamond&quot; shape will be saved and it will be used in all future SocNetV sessions to create new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> + + + + + + + :/images/diamond.png:/images/diamond.png + + + + + + + + DejaVu Sans + 11 + + + + <html><head/><body><p><span style=" font-weight:600;">Node shape: Ellipse</span></p><p>Change all node shapes to &quot;ellipse&quot;.</p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the &quot;ellipse&quot; shape will be saved and it will be used in all future SocNetV sessions when creating new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> + + + + + + + :/images/ellipse.png:/images/ellipse.png + + + + + + + + DejaVu Sans + 11 + + + + <html><head/><body><p><span style=" font-weight:600;">Node shape: Star</span></p><p>Change all node shapes to &quot;star&quot;.</p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the &quot;star&quot; shape will be saved and it will be used in all future SocNetV sessions to create new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> + + + + + + + :/images/triangle.png:/images/triangle.png + + + + + + + + DejaVu Sans + 11 + + + + <html><head/><body><p><span style=" font-weight:600;">Node shape: Triangle</span></p><p>Change all node shapes to &quot;triangle&quot;.</p><p>This will apply to all existing nodes immediately.</p><p>Once you press OK, the &quot;triangle&quot; shape will be saved and it will be used in all future SocNetV sessions to create new nodes (except when loading network files which declare specific shapes for nodes).</p></body></html> + + + + + + + :/images/star.png:/images/star.png + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node size</span></p><p>Use the spin box to select a new size (in pixels) for all nodes. </p><p>Actual node size will vary according to selected shape. For instance, if the selected shape is circle and the selected size is 8, then the circle will have a diameter of 16 pixels. </p><p>Any change to this setting will apply to all existing nodes immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node size when creating new nodes (except when loading network files which declare specific node settings).</p></body></html> + + + Node size + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + SizeVerCursor + + + <html><head/><body><p><span style=" font-weight:600;">Node size</span></p><p>Select a new size for all nodes. Actual node size will vary according to selected shape. For instance, if the selected shape is circle and the size is 8, then the circle will have a diameter of 16 pixels. </p><p>Any change to this setting will apply to all existing nodes immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node size.</p></body></html> + + + 1 + + + 8 + + + + + + + + + + + + Node Number settings + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node number color</span></p><p>Change the color for all node numbers. Click the colored button on the right corner to select a new color.</p><p>Any change to this setting will apply to all existing node numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node number color when creating new nodes.</p></body></html> + + + Number color + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Node number color</span></p><p>Click to select a new color for all node numbers.</p><p>Any change to this setting will apply to all existing node numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node number color when creating new nodes.</p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Number distance from node</span></p><p>Change the distance of each number from the respective node. Use the spin box on the right to select a new distance (in pixels).</p><p>Any change to this setting will apply to all existing node numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default distance from node.</p></body></html> + + + Number distance + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + SizeVerCursor + + + <html><head/><body><p><span style=" font-weight:600;">Number distance from nodes</span></p><p>Select a new distance (in pixels) of numbers from the respective nodes.</p><p>Any change to this setting will apply to all existing node numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default distance from node.</p></body></html> + + + 1 + + + 8 + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node numbers</span></p><p>Enable or disable displaying node numbers.</p><p>Any change will apply to all existing nodes immediately.</p><p>Once you press OK, this setting will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Node numbers</span></p><p>Enable or disable displaying node numbers.</p><p>Any change will apply to all existing nodes immediately.</p><p>Once you press OK, this setting will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + Qt::LeftToRight + + + Display node numbers + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node number font size</span></p><p>Change the font size (in pixels) of all node numbers. Use the spin box on the right to select a new font size (in pixels).</p><p>Any change to this setting will apply to all existing node numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node number size.</p></body></html> + + + Number font size + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + SizeVerCursor + + + <html><head/><body><p><span style=" font-weight:600;">Node number size</span></p><p>Select a new font size (in pixels) for node numbers. Set it to 0 to let the program automagically select a different font size according to the node size.</p><p>Any change to this setting will apply to all existing node numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node number size.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Node number size</span></p><p>Select a new font size (in pixels) for node numbers. Set it to 0 to let the program automagically select a different font size according to the node size.</p><p>Any change to this setting will apply to all existing node numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node number size.</p></body></html> + + + 8 + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node numbers inside shapes</span></p><p>Enable or disable displaying node numbers inside the node shapes</p><p>Any change will apply to all existing nodes immediately.</p><p>Once you press OK, this setting will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Node numbers inside shapes</span></p><p>Enable or disable displaying node numbers inside the node shapes</p><p>Any change will apply to all existing nodes immediately.</p><p>Once you press OK, this setting will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + Qt::LeftToRight + + + Display node numbers inside node shapes + + + + + + + + + + Node Label settings + + + + + + <html><head/><body><p><span style=" font-weight:600;">Node labels</span></p><p>Enable or disable displaying labels below the nodes.</p><p>Any change will apply to all existing nodes immediately.</p><p>Once you press OK, this setting will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Node labels</span></p><p>Enable or disable displaying labels below the nodes.</p><p>Any change will apply to all existing nodes immediately.</p><p>Once you press OK, this setting will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + Qt::LeftToRight + + + Display node labels + + + + + + + + + Label color + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Node label color</span></p><p>Click to select a new color for node labels.</p><p>Any change to this setting will apply to all existing node labels immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node label color.</p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + Label font size + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + SizeVerCursor + + + <html><head/><body><p><span style=" font-weight:600;">Node label size</span></p><p>Select a new font size (in pixels) for all node labels.</p><p>Any change to this setting will apply to all existing node labels immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default node label size.</p></body></html> + + + 8 + + + + + + + + + + + Label distance + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + SizeVerCursor + + + <html><head/><body><p><span style=" font-weight:600;">Label distance from node</span></p><p>Change the distance of labels from the respective nodes.</p><p>Any change to this setting will apply to all existing node labels immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default label distance from node.</p></body></html> + + + 8 + + + + + + + + + + groupBox_3 + groupBox_4 + groupBox_7 + + + + Edges + + + + + + Edge settings + + + + + + <html><head/><body><p><span style=" font-weight:600;">Edges </span></p><p>Enable or disable displaying edges.</p><p>Any change will apply to all existing edges immediately.</p><p><br/></p></body></html> + + + Qt::LeftToRight + + + Display edges + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Edge color</span></p><p>Click the colored button on the right to select a new color for all edges.</p><p>Any change to this setting will apply to all existing edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge color. Until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Edge color</span></p><p>Click the colored button on the right to select a new color for all edges.</p><p>Any change to this setting will apply to all existing edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge color. Until you change it again.</p></body></html> + + + Edge color + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Edge color</span></p><p>Click to select a new color for all edges.</p><p>Any change to this setting will apply to all existing edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge color. Until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Edge color</span></p><p>Click to select a new color for all edges.</p><p>Any change to this setting will apply to all existing edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge color. Until you change it again.</p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Negative edge color</span></p><p>Click the colored button at the right corner to select a new color for negative weighted edges.</p><p>Any change to this setting will apply to all existing &quot;negative&quot; edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge color for &quot;negative&quot; edges. Until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Negative edge color</span></p><p>Click the colored button at the right corner to select a new color for negative weighted edges.</p><p>Any change to this setting will apply to all existing &quot;negative&quot; edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge color for &quot;negative&quot; edges. Until you change it again.</p></body></html> + + + Edge color (negative weights) + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Negative edge color</span></p><p>Click this button to select a new default edge color for all negative weighted edges.</p><p>Any change to this setting will apply to all existing &quot;negative&quot; edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default color for &quot;negative&quot; edges. Until you change it again.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Negative edge color</span></p><p>Click this button to select a new default edge color for all negative weighted edges.</p><p>Any change to this setting will apply to all existing &quot;negative&quot; edges immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default color for &quot;negative&quot; edges. Until you change it again.</p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Default edge shape</span></p><p>Select the default edge shape for all edges. </p><p>Edges can be either straight lines (default) or bezier curves.</p><p>This will apply to all existing edgesimmediately.</p><p>Once you press OK, the default edge shape will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Default edge shape</span></p><p>Select the default edge shape for all edges. </p><p>Edges can be either straight lines (default) or bezier curves.</p><p>This will apply to all existing edgesimmediately.</p><p>Once you press OK, the default edge shape will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + Edge shape + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Default edge shape</span></p><p>Select the default edge shape for all edges. </p><p>Edges can be either straight lines (default) or bezier curves.</p><p>This will apply to all existing edgesimmediately.</p><p>Once you press OK, the default edge shape will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Default edge shape</span></p><p>Select the default edge shape for all edges. </p><p>Edges can be either straight lines (default) or bezier curves.</p><p>This will apply to all existing edgesimmediately.</p><p>Once you press OK, the default edge shape will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + Straight Lines + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Default edge shape</span></p><p>Select the default edge shape for all edges. </p><p>Edges can be either straight lines (default) or bezier curves.</p><p>This will apply to all existing edgesimmediately.</p><p>Once you press OK, the default edge shape will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Default edge shape</span></p><p>Select the default edge shape for all edges. </p><p>Edges can be either straight lines (default) or bezier curves.</p><p>This will apply to all existing edgesimmediately.</p><p>Once you press OK, the default edge shape will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + Bezier Curves + + + + + + + + + + + + Weight number settings + + + + + + <html><head/><body><p><span style=" font-weight:600;">Edge weight numbers</span></p><p>Enable or disable edge weight numbers. When enabled, a number will be displayed along every edge indicating the edge weight.</p><p>Any change to this setting will apply to all existing weight numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default when creating new edges.</p></body></html> + + + Qt::LeftToRight + + + Display edge weight numbers + + + + + + + + + Weight number color + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Edge weight number color</span></p><p>Click to select a new color for all edge weight numbers.</p><p>Any change to this setting will apply to all existing weight numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge weight number color when creating new edges.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Edge weight number color</span></p><p>Click to select a new color for all edge weight numbers.</p><p>Any change to this setting will apply to all existing weight numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge weight number color when creating new edges.</p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + Weight number font size + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + SizeVerCursor + + + <html><head/><body><p><span style=" font-weight:600;">Edge weight number text size</span></p><p>Click to select a new text size (in pixels) for all edge weight numbers.</p><p>Any change to this setting will apply to all existing weight numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge weight number size when creating new edges.</p></body></html> + + + <html><head/><body><p><span style=" font-weight:600;">Edge weight number text size</span></p><p>Click to select a new text size (in pixels) for all edge weight numbers.</p><p>Any change to this setting will apply to all existing weight numbers immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge weight number size when creating new edges.</p></body></html> + + + 8 + + + + + + + + + + + + Edge label settings + + + + + + <html><head/><body><p><span style=" font-weight:600;">Edge labels</span></p><p>Enable or disable displaying edge labels.</p><p>Any change will apply to all existing edges immediately.</p><p>Once you press OK, this setting will be saved and it will be used in all future SocNetV sessions.</p></body></html> + + + Qt::LeftToRight + + + Display edge labels + + + + + + + + + Label color + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 25 + + + + + DejaVu Sans + 11 + + + + PointingHandCursor + + + <html><head/><body><p><span style=" font-weight:600;">Default edge label color</span></p><p>Click to select a new default color for edge labels.</p><p>Any change to this setting will apply to all existing edge labels immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge label color.</p></body></html> + + + ... + + + + 60 + 20 + + + + + + + + + + + + Label font size + + + + + + + + DejaVu Sans + 11 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + DejaVu Sans + 11 + + + + SizeVerCursor + + + <html><head/><body><p><span style=" font-weight:600;">Default edge label size</span></p><p>Select the default font size for all edge labels.</p><p>Any change to this setting will apply to all existing edge labels immediately.</p><p>This is a permanent setting. Once you press OK, it will be saved and used in all future SocNetV sessions as default edge label size.</p></body></html> + + + 8 + + + + + + + + + + + + + + + + + + + + buttonBox + accepted() + SettingsDialog + accept() + + + 227 + 281 + + + 157 + 274 + + + + + buttonBox + rejected() + SettingsDialog + reject() + + + 295 + 287 + + + 286 + 274 + + + + + diff --git a/src/forms/webcrawlerdialog.ui b/src/forms/webcrawlerdialog.ui index 25347201..61142628 100644 --- a/src/forms/webcrawlerdialog.ui +++ b/src/forms/webcrawlerdialog.ui @@ -7,7 +7,7 @@ 0 0 500 - 310 + 334 @@ -19,29 +19,23 @@ 500 - 310 + 330 627 - 350 + 380 - - - DejaVu Sans Mono - 12 - - Generate network from web links - - + + - + 0 0 @@ -54,13 +48,11 @@ - DejaVu Sans - 11 - PreferAntialias + 10 - <html><head/><body><p>SocNetV includes a simple web crawler. It scans the HTML code of a given initial URL (i.e. a website) and maps all internal or external links to other pages found there. As new urls are discovered, the crawler follows them to scan their HTML code for links as well. For more details, see the Manual.</p></body></html> + <html><head/><body><p>SocNetV includes a simple web crawler. It scans the HTML code of a given initial URL (i.e. a website) and maps all internal or external links to other pages found there. As new urls are discovered, the crawler follows them to scan their HTML code for links as well. For more details, see the Manual. </p><p>Enter the initial URL below and change crawling parameters if you like.</p></body></html> Qt::RichText @@ -70,7 +62,7 @@ - + @@ -90,11 +82,7 @@ - DejaVu Sans - 11 - 50 - false - PreferAntialias + 10 @@ -102,10 +90,16 @@ + + + 0 + 0 + + 250 - 32 + 26 @@ -114,70 +108,38 @@ 32 - - - DejaVu Sans - 11 - PreferAntialias - - <html><head/><body><p>Enter the initial url/domain to start crawling from, i.e. http://www.iefimerida.gr </p><p>You may omit http:// if you want. </p></body></html> - - - - - - - 11 - PreferAntialias - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - + + + + - 201 + 230 0 - DejaVu Sans - 11 - 50 - false - PreferAntialias + 10 - Set the max links inside a page to be followed and crawled by SocNetV. - - Set this to zero if you don't want to have this limit. -In this case SocNetV will follow and crawl each one link found in a page. + Set the total urls to be crawled - this is the total nodes the result network will have. +Set value to 0, if you don't want any limits... - Max links in each page to follow + Total urls to crawl - - + + 11 @@ -195,8 +157,8 @@ In this case SocNetV will follow and crawl each one link found in a page. - - + + 46 @@ -205,55 +167,77 @@ In this case SocNetV will follow and crawl each one link found in a page. - 11 - PreferAntialias + 10 - Set the max links inside a page to be followed and crawled by SocNetV. - - Set this to zero if you don't want to have this limit. -In this case SocNetV will follow and crawl each one link found in a page. + Set the total urls to be crawled - this is the total nodes the result network will have. +Set value to 0, if you don't want any limits... + + + Set the total urls to be crawled - this is the total nodes the result network will have. +Set value to 0, if you don't want any limits... 0 - 500 + 9999 - 0 + 600 - - + + + + + + - 230 + 201 0 - DejaVu Sans - 11 - 50 - false - PreferAntialias + 10 - Set the total urls to be crawled - this is the total nodes the result network will have. -Set value to 0, if you don't want any limits... + Set the max links inside a page to be followed and crawled by SocNetV. + + Set this to zero if you don't want to have this limit. +In this case SocNetV will follow and crawl each one link found in a page. - Total urls to crawl + Max links in each page to follow - - + + + + + 11 + PreferAntialias + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + 46 @@ -262,36 +246,30 @@ Set value to 0, if you don't want any limits... - 11 - PreferAntialias + Sans Serif + 10 - Set the total urls to be crawled - this is the total nodes the result network will have. -Set value to 0, if you don't want any limits... - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Maximum Nodes to display</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In this spinbox, you define the maximum nodes to be displayed by SocNetV when running in Web Crawler mode. Set value to 0, if you don't want any limits...</p></body></html> + Set the max links inside a page to be followed and crawled by SocNetV. + + Set this to zero if you don't want to have this limit. +In this case SocNetV will follow and crawl each one link found in a page. 0 - 9999 + 500 - 600 + 0 - + @@ -301,9 +279,7 @@ p, li { white-space: pre-wrap; } - DejaVu Sans - 11 - PreferAntialias + 10 @@ -319,20 +295,18 @@ p, li { white-space: pre-wrap; } Crawl external links - true + false false - + - DejaVu Sans - 11 - PreferAntialias + 10 @@ -352,16 +326,15 @@ p, li { white-space: pre-wrap; } - + true - DejaVu Sans - 11 - PreferAntialias + Sans Serif + 10 @@ -383,8 +356,8 @@ p, li { white-space: pre-wrap; } accept() - 248 - 254 + 257 + 324 157 @@ -399,8 +372,8 @@ p, li { white-space: pre-wrap; } reject() - 316 - 260 + 325 + 324 286 diff --git a/src/graph.cpp b/src/graph.cpp index 5da54d3a..6a284471 100755 --- a/src/graph.cpp +++ b/src/graph.cpp @@ -5,7 +5,7 @@ graph.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -39,12 +39,17 @@ #include //allows the use of RAND_MAX macro #include #include //for BFS queue Q -#include // for makeThingsLookRandom +#include // for randomizeThings static qreal Pi = 3.14159265; + +/** + * @brief Graph::Graph + * constructor + */ Graph::Graph() { m_totalVertices=0; outboundEdgesVert=0; @@ -67,9 +72,6 @@ Graph::Graph() { calculatedTriad=false; m_precision = 5; m_curRelation=0; - dynamicMovement=false; - timerId=0; - layoutType=0; file_parser = 0; wc_parser = 0; @@ -79,34 +81,52 @@ Graph::Graph() { influenceDomains.reserve(1000); influenceRanges.reserve(1000); +} + + +/** + * @brief Graph::canvasSizeSet + * Called when MW and GraphicsWidget resizes to update canvasWidth and canvasHeight + * @param w + * @param h + */ +void Graph::canvasSizeSet(const int w, const int h){ + qDebug() << "Graph:: canvasSizeSet() - (" << w << ", " << h<<")"; + canvasWidth = w-50; + canvasHeight= h-50; +} + +double Graph::canvasMinDimension () const { + return ( canvasHeight < canvasWidth ) ? canvasHeight / 2.0 -20 : canvasWidth/2.0 - 20; } + /** - * @brief Graph::changeRelation + * @brief Graph::relationSet * Called from MW and Parser * @param relation */ -void Graph::changeRelation(int relation){ - qDebug() << "++ Graph::changeRelation(int) to relation " << relation +void Graph::relationSet(int relation){ + qDebug() << "++ Graph::relationSet(int) to relation " << relation << " current relation is " << m_curRelation ; if (m_curRelation == relation ) { - qDebug() << "++ Graph::changeRelation(int) - same relation - END"; + qDebug() << "++ Graph::relationSet(int) - same relation - END"; return; } if ( relation < 0) { - qDebug() << "++ Graph::changeRelation(int) - negative relation - END "; + qDebug() << "++ Graph::relationSet(int) - negative relation - END "; return; } QList::const_iterator it; for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ if ( ! (*it)->isEnabled() ) continue; - (*it)->changeRelation(relation); + (*it)->relationSet(relation); } m_curRelation = relation; emit relationChanged(m_curRelation); @@ -120,9 +140,9 @@ void Graph::changeRelation(int relation){ * @brief Called from MW to add a relation and change to that new relation * @param newRelation */ -void Graph::addRelationFromUser(QString newRelation){ +void Graph::relationAddFromUser(QString newRelation){ m_relationsList << newRelation; - qDebug() << "Graph::addRelationFromUser(string) " << newRelation + qDebug() << "Graph::relationAddFromUser(string) " << newRelation << " total relations now " << relations() ; } @@ -132,8 +152,8 @@ void Graph::addRelationFromUser(QString newRelation){ * emits addRelationToMW * @param newRelation */ -void Graph::addRelationFromGraph(QString newRelation) { - qDebug() << "Graph::addRelationFromGraph(string) " << newRelation; +void Graph::relationAddFromGraph(QString newRelation) { + qDebug() << "Graph::relationAddFromGraph(string) " << newRelation; m_relationsList << newRelation; emit addRelationToMW(newRelation); } @@ -143,8 +163,8 @@ void Graph::addRelationFromGraph(QString newRelation) { * emits addRelationToMW * @param newRelation */ -void Graph::addRelationFromParser(QString newRelation) { - qDebug() << "Graph::addRelationFromParser(string) " << newRelation; +void Graph::relationAddFromParser(QString newRelation) { + qDebug() << "Graph::relationAddFromParser(string) " << newRelation; m_relationsList << newRelation; emit addRelationToMW(newRelation); } @@ -153,7 +173,7 @@ void Graph::addRelationFromParser(QString newRelation) { * @brief Returns current relation index * @return int current relation index */ -int Graph::currentRelation(){ +int Graph::relationCurrent(){ return m_curRelation; } @@ -165,38 +185,67 @@ int Graph::relations(){ /** - main node creation slot, associated with homonymous signal from Parser. - Adds a Vertex to the Graph and calls addNode of GraphicsWidget - p holds the desired position of the new node. - The new Vertex is named i and stores its color, label, label color, shape and position p. + */ -void Graph::createVertex(int i, int size, QString nodeColor, QString numColor, - int numSize, QString label, QString lColor, int lSize, - QPointF p, QString nodeShape, bool signalMW){ +/** + * @brief Graph::vertexCreate + * Main vertex creation slot, associated with homonymous signal from Parser. + * Adds a Vertex to the Graph and calls editNodeAdd of GraphicsWidget + * The new Vertex is named i and stores its color, label, label color, shape and position p. + * p holds the desired position of the new node. + * @param num + * @param size + * @param nodeColor + * @param numColor + * @param numSize + * @param label + * @param lColor + * @param lSize + * @param p + * @param nodeShape + * @param signalMW + */ +void Graph::vertexCreate(const int &num, const int &nodeSize, const QString &nodeColor, + const QString &numColor, const int &numSize, + const QString &label, const QString &labelColor, + const int &labelSize, + const QPointF &p, const QString &nodeShape, + const bool &signalMW){ int value = 1; - addVertex(i, value, size, nodeColor, numColor, numSize, label, lColor, lSize, p, nodeShape); - emit drawNode( i, size, nodeColor, numColor, numSize, label, lColor, lSize, - p, nodeShape, initShowLabels, initNumbersInsideNodes, true); + qDebug() << "Graph::vertexCreate() " << num ; + vertexAdd ( num, value, nodeSize, nodeColor, + numColor, numSize, + label, labelColor, labelSize, p, nodeShape); + + + emit drawNode( num, nodeSize, nodeShape, nodeColor, + initVertexNumbersVisibility, initNumbersInsideNodes, + numColor, numSize, + initVertexLabelsVisibility, label, + labelColor, labelSize, + p ); + if (signalMW) emit graphChanged(); + //draw new user-clicked nodes with the same color with that of the file loaded initVertexColor=nodeColor; initVertexShape=nodeShape; - initVertexSize=size; + initVertexSize=nodeSize; } /** - auxilliary node creation slot. + auxilliary vertex creation slot. Called from GW, with i and p as parameters. p holds the desired position of the new node. Calls the main creation slot with init node values. */ -void Graph::createVertex(int i, QPointF p){ - if ( i < 0 ) i = lastVertexNumber() +1; - qDebug() << "Graph::createVertex() " << i << " fixed coords."; - createVertex( i, initVertexSize, initVertexColor, +void Graph::vertexCreate(const QPointF &p){ + int i = vertexLastNumber() +1; + qDebug() << "Graph::vertexCreate() " << i << " fixed coords."; + vertexCreate( i, initVertexSize, initVertexColor, initVertexNumberColor, initVertexNumberSize, QString::number(i), initVertexLabelColor, initVertexLabelSize, p, initVertexShape, true @@ -207,18 +256,18 @@ void Graph::createVertex(int i, QPointF p){ /** - second auxilliary node creation slot. + second auxilliary vertex creation slot. Called from MW only with parameter i. Calculates a random position p from canvasWidth and Height. Then calls the main creation slot with init node values. */ -void Graph::createVertex(int i, int cWidth, int cHeight){ - if ( i < 0 ) i = lastVertexNumber() +1; - qDebug() << "Graph::createVertex() " << i << " random coords."; +void Graph::vertexCreate(int i){ + if ( i < 0 ) i = vertexLastNumber() +1; + qDebug() << "Graph::vertexCreate() " << i << " random coords."; QPointF p; - p.setX(rand()%cWidth); - p.setY(rand()%cHeight); - createVertex( i, initVertexSize, initVertexColor, + p.setX(10 + rand()%canvasWidth); + p.setY(10 + rand()%canvasWidth); + vertexCreate( i, initVertexSize, initVertexColor, initVertexNumberColor, initVertexNumberSize, QString::number(i), initVertexLabelColor, initVertexLabelSize, p, initVertexShape, true @@ -234,13 +283,13 @@ void Graph::createVertex(int i, int cWidth, int cHeight){ Then calls the main creation slot with init node values. */ -void Graph::createVertexWebCrawler(QString label, int i) { - if ( i < 0 ) i = lastVertexNumber() +1; - qDebug() << "Graph::createVertexWebCrawler() " << i << " rand coords with label"; +void Graph::vertexCreateWebCrawler(const QString &label, const int &i) { + + qDebug() << "Graph::vertexCreateWebCrawler() " << i << " label" << label; QPointF p; - p.setX(rand()%canvasWidth); - p.setY(rand()%canvasHeight); - createVertex( i, initVertexSize, initVertexColor, + p.setX(10 + rand()%canvasWidth); + p.setY(10 + rand()%canvasHeight); + vertexCreate( (i<0)?vertexLastNumber() +1:i, initVertexSize, initVertexColor, initVertexNumberColor, initVertexNumberSize, label, initVertexLabelColor, initVertexLabelSize, p, initVertexShape, true @@ -249,94 +298,6 @@ void Graph::createVertexWebCrawler(QString label, int i) { } -void Graph::setCanvasDimensions(int w, int h){ - qDebug() << "Graph:: setCanvasDimensions() to " << w << " " << h ; - canvasWidth = w; - canvasHeight= h; -} - - -/** - * @brief Adds an Edge to the Graph, then emits drawEdge() which calls - GraphicsWidget::addEdge() to draw the new edge. - Called from homonymous signal of Parser class. - Also called from MW when user clicks on the "add link" button - Alse called from GW (via createEdge() below) when user middle-clicks. - * @param v1 - * @param v2 - * @param weight - * @param color - * @param reciprocal - * @param drawArrows - * @param bezier - */ -void Graph::createEdge(int v1, int v2, float weight, QString color, - int reciprocal=0, bool drawArrows=true, bool bezier=false){ - qDebug()<<"-- Graph::createEdge() - " << v1 << " -> " << v2 - << " weight " << weight - << " reciprocal " << reciprocal; - // check whether there is already such an edge - // (see #713617 - https://bugs.launchpad.net/socnetv/+bug/713617) - if (!hasArc(v1,v2)){ - if ( reciprocal == 2) { - qDebug()<< "-- Graph::createEdge() - " - << "Creating RECIPROCAL edge - emitting drawEdge signal to GW"; - addEdge ( v1, v2, weight, color, reciprocal); - emit drawEdge(v1, v2, weight, reciprocal, drawArrows, color, bezier); - } - else if (this->hasArc( v2, v1) ) { - qDebug()<<"-- Graph::createEdge() - Opposite arc exists. " - << " Emitting drawEdgeReciprocal to GW "; - reciprocal = 1; - addEdge ( v1, v2, weight, color, reciprocal); - emit drawEdgeReciprocal(v2, v1); - } - else { - qDebug()<< "-- Graph::createEdge() - " - << "Opposite arc does not exist. Emitting drawEdge to GW..."; - reciprocal = 0; - addEdge ( v1, v2, weight, color, reciprocal); - emit drawEdge(v1, v2, weight, reciprocal, drawArrows, color, bezier); - } - } - else { - qDebug() << "-- Graph::createEdge() - " - << "Edge " << v1 << " -> " << v2 - << " declared previously (exists) - nothing to do \n\n"; - } - //draw new edges the same color with those of the file loaded, - // on user clicks on the canvas - initEdgeColor=color; - emit graphChanged(); -} - - -/** - Called (via MW::addLink()) from GW when user middle-clicks on two nodes. - Calls the above createEdge() method with initEdgeColor to set the default edge color. -*/ -void Graph::createEdge(int v1, int v2, float weight, int reciprocal=0, - bool drawArrows=true, bool bezier=false){ - qDebug()<< "Graph::createEdge() - " << v1<< " -> " << v2 ; - createEdge(v1, v2, (float) weight, initEdgeColor, reciprocal, - drawArrows, bezier); -} - - -/** - Called from WebCrawler when it finds an new link - Calls the above createEdge() method with initEdgeColor -*/ -void Graph::createEdgeWebCrawler (int source, int target){ - qDebug()<< " Graph::createEdgeWebCrawler() - from " << source << " to " << target ; - float weight = 1.0; - bool reciprocal=false; - bool drawArrows=true; - bool bezier=false; - - createEdge(source, target, weight, initEdgeColor, reciprocal, drawArrows, bezier); -} - /** * @brief Deletes any dymmy nodes @@ -344,9 +305,9 @@ void Graph::createEdgeWebCrawler (int source, int target){ * redundant (dummy) nodes. * @param [in] i number of node */ -void Graph::removeDummyNode(int i){ - qDebug("**Graph: RemoveDummyNode %i", i); - removeVertex(i); +void Graph::vertexRemoveDummyNode(int i){ + qDebug("**Graph::vertexRemoveDummyNode %i", i); + vertexRemove(i); } @@ -355,7 +316,7 @@ void Graph::removeDummyNode(int i){ /** * @brief Adds a Vertex named v1, valued val, sized nszm colored nc, labeled nl, * labelColored lc, shaped nsp, at point p. - * This method is called by createVertex() method + * This method is called by vertexCreate() method * @param v1 * @param val * @param size @@ -368,14 +329,13 @@ void Graph::removeDummyNode(int i){ * @param p * @param shape */ -void Graph::addVertex ( - int v1, int val, int size, QString color, - QString numColor, int numSize, - QString label, QString labelColor, int labelSize, - QPointF p, QString shape - ){ +void Graph::vertexAdd ( const int &v1, const int &val, const int &size, + const QString &color, const QString &numColor, + const int &numSize, const QString &label, + const QString &labelColor, const int &labelSize, + const QPointF &p, const QString &shape ){ - qDebug() << "Graph::addVertex() "; + qDebug() << "Graph::vertexAdd() "; if (order) index[v1]=m_totalVertices; else @@ -389,7 +349,7 @@ void Graph::addVertex ( ); m_totalVertices++; -// qDebug() << "Graph: addVertex(): Vertex named " << m_graph.back()->name() +// qDebug() << "Graph: vertexAdd(): Vertex named " << m_graph.back()->name() // << " appended with index= "<0) return m_graph.back()->name(); else return 0; } -/** Returns the name of the first vertex. - Used by slotRemoveNode of MW -*/ -int Graph::firstVertexNumber() { + +/** + * @brief Graph::vertexFirstNumber + * Returns the name of the first vertex. Used by slotRemoveNode of MW + * @return int + */ +int Graph::vertexFirstNumber() { if (m_totalVertices>0) return m_graph.front()->name(); else return 0; @@ -436,55 +388,57 @@ int Graph::firstVertexNumber() { -/** Removes the vertex named Doomed from the graph - First, it removes all edges to Doomed from other vertices - Then it changes the index of all subsequent vertices inside m_graph - Finally, it removes the vertex. -*/ -void Graph::removeVertex(long int Doomed){ - qDebug() << "Graph: removeVertex - Doomed: " + +/** + * @brief Graph::vertexRemove + * Removes the vertex named Doomed from the graph + * First, it removes all edges to Doomed from other vertices + * Then it changes the index of all subsequent vertices inside m_graph + * Finally, it removes the vertex. + * @param Doomed + */ +void Graph::vertexRemove(long int Doomed){ + qDebug() << "Graph::vertexRemove() - doomed: " << m_graph[ index[Doomed] ]->name() - << " indexOfDoomed= " << index[Doomed] ; + << " index: " << index[Doomed] + << " Removing all inbound and outbound edges "; long int indexOfDoomed=index[Doomed]; //Remove links to Doomed from each other vertex QList::const_iterator it; for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ if ( (*it)->hasEdgeTo(Doomed) != 0) { - qDebug()<< "Graph: Vertex " << (*it)->name() - << " is linked to doomed "<< Doomed << " and has " - << (*it)->outEdges() << " and " << (*it)->outDegree() ; - if ( (*it)->outEdges() == 1 && (*it)->hasEdgeFrom(Doomed) != 0 ) { - // qDebug() << "Graph: decreasing reciprocalEdgesVert"; - (*it)->setReciprocalLinked(false); - } - (*it)->removeEdgeTo(Doomed) ; + qDebug()<< "Graph::vertexRemove() - vertex " << (*it)->name() + << " has outbound Edge to "<< Doomed << ". Removing it."; + (*it)->edgeRemoveTo(Doomed) ; } if ( (*it)->hasEdgeFrom(Doomed) != 0 ) { - (*it)->removeEdgeFrom(Doomed); + qDebug()<< "Graph::vertexRemove() - vertex " << (*it)->name() + << " has inbound Edge from "<< Doomed << ". Removing it."; + (*it)->edgeRemoveFrom(Doomed); } } - qDebug()<< "Graph: Finished with vertices. Update the index which maps vertices inside m_graph " ; + qDebug()<< "Graph::vertexRemove() - Finished with vertices. Update the index which maps vertices inside m_graph " ; long int prevIndex=indexOfDoomed; - qDebug () << " Updating index of all subsequent vertices "; + qDebug()<< "Graph::vertexRemove() - Updating index of all subsequent vertices "; H_Int::const_iterator it1=index.cbegin(); while (it1 != index.cend()){ if ( it1.value() > indexOfDoomed ) { prevIndex = it1.value(); - qDebug() << "Graph::removeVertex - vertex " << it1.key() + qDebug() << "Graph::vertexRemove() - vertex " << it1.key() << " had prevIndex: " << prevIndex << " > indexOfDoomed " << indexOfDoomed << " Setting new index. Index size was: "<< index.size(); index.insert( it1.key(), --prevIndex) ; - qDebug() << "Graph::removeVertex - vertex " << it1.key() + qDebug() << "Graph::vertexRemove() - vertex " << it1.key() << " new index: " << index.value( it1.key(), -666) << " Index size now: "<< index.size(); } else { - qDebug() << "Graph::removeVertex " << it1.key() << " with index " + qDebug() << "Graph::vertexRemove() " << it1.key() << " with index " << it1.value() << " < indexOfDoomed. CONTINUE"; } @@ -492,12 +446,12 @@ void Graph::removeVertex(long int Doomed){ } //Now remove vertex Doomed from m_graph - qDebug() << "Graph: graph vertices=size="<< vertices() << "=" + qDebug()<< "Graph::vertexRemove() - graph vertices=size="<< vertices() << "=" << m_graph.size() << " removing vertex at index " << indexOfDoomed ; m_graph.removeAt( indexOfDoomed ) ; m_totalVertices--; - qDebug() << "Graph: Now graph vertices=size="<< vertices() << "=" - << m_graph.size() << " total edges now " << enabledEdges(); + qDebug()<< "Graph::vertexRemove() - Now graph vertices=size="<< vertices() << "=" + << m_graph.size() << " total edges now " << edgesEnabled(); order=false; graphModified=true; @@ -508,183 +462,18 @@ void Graph::removeVertex(long int Doomed){ -/** - * Creates an edge between v1 and v2 -*/ -void Graph::addEdge (int v1, int v2, float weight, QString color, int reciprocal) { - - int source=index[v1]; - int target=index[v2]; - - qDebug()<< "Graph: addEdge() from vertex "<< v1 << "["<< source - << "] to vertex "<< v2 << "["<< target << "] of weight "<addEdgeTo(v2, weight ); - m_graph [ target ]->addEdgeFrom(v1, weight); - - if (reciprocal == 1){ - m_graph [ source ]->setReciprocalLinked(true); - m_graph [ target ]->setReciprocalLinked(true); - } - else if (reciprocal == 2){ - m_graph [ source ]->setReciprocalLinked(true); - m_graph [ target ]->setReciprocalLinked(true); - m_graph [ target ]->addEdgeTo(v1, weight ); - m_graph [ source ]->addEdgeFrom(target, weight); - } - -// qDebug()<<"Graph: addEdge() now a("<< v1 << ","<< v2<< ") = " << weight -// << " with color "<< color -// <<" . Storing edge color..." ; - m_graph[ source]->setOutLinkColor(v2, color); - - graphModified=true; -} - - - - -/** - Change edge (arc) weight between v1 and v2 -*/ -void Graph::setArcWeight (const long &v1, const long &v2, const float &weight) { - qDebug() << "Graph::setArcWeight between " << v1 << "[" << index[v1] - << "] and " << v2 << "[" << index[v2] << "]" << " = " << weight; - m_graph [ index[v1] ]->changeOutEdgeWeight(v2, weight); - graphModified=true; - emit graphChanged(); - -} - - -/** Removes the edge (arc) between v1 and v2 -*/ -void Graph::removeEdge (int v1, int v2) { - qDebug ()<< "\n\n Graph::removeEdge() edge from " << v1 << " index " << index[v1] - << " to " << v2 << " to be removed from graph"; - m_graph [ index[v1] ]->removeEdgeTo(v2); - m_graph [ index[v2] ]->removeEdgeFrom(v1); -// qDebug()<< "Graph: removeEdge between " << v1 << " i " << index[v1] -// << " and " << v2 << " i "<< index[v2] -// << " NOW vertex v1 reports edge weight " -// << m_graph [ index[v1] ]->hasEdgeTo(v2) ; - if ( this->hasArc(v2,v1) !=0) - symmetricAdjacencyMatrix=false; - - graphModified=true; - - emit eraseEdge(v1,v2); - emit graphChanged(); -} - - - - - -//Called by MW to start a web crawler... -void Graph::webCrawl( QString seed, int maxNodes, int maxRecursion, - bool extLinks, bool intLinks){ - - qDebug() << "Graph::webCrawl() - seed " << seed ; - //WebCrawler *crawler = new WebCrawler; - - qDebug() << "Graph::webCrawl() Creating wc_spider & wc_parser objects"; - WebCrawler_Parser *wc_parser = new WebCrawler_Parser(seed, maxNodes, - maxRecursion, - extLinks, - intLinks); - WebCrawler_Spider *wc_spider = new WebCrawler_Spider (seed, maxNodes, - maxRecursion, - extLinks, intLinks); - - qDebug() << "Graph::webCrawl() Moving parser & spider to new QThreads!"; - qDebug () << " graph thread " << this->thread(); - qDebug () << " wc_parser thread " << wc_parser->thread(); - qDebug () << " wc_spider thread " << wc_spider->thread(); - wc_parser->moveToThread(&wc_parserThread); - wc_spider->moveToThread(&wc_spiderThread); - qDebug () << " graph thread is " << this->thread(); - qDebug () << " wc_parser thread now " << wc_parser->thread(); - qDebug () << " wc_spider thread now " << wc_spider->thread(); - - - qDebug() << "Graph::webCrawl() Connecting signals from/to parser & spider"; - connect(&wc_parserThread, &QThread::finished, - wc_parser, &QObject::deleteLater); - - connect(&wc_spiderThread, &QThread::finished, - wc_spider, &QObject::deleteLater); - - connect(this, &Graph::operateSpider, - wc_spider, &WebCrawler_Spider::get); - - connect(wc_parser, &WebCrawler_Parser::signalCreateNode, - this, &Graph::createVertexWebCrawler); - - connect(wc_parser, &WebCrawler_Parser::signalCreateEdge, - this, &Graph::createEdgeWebCrawler); - - connect (wc_spider, &WebCrawler_Spider::finished, - this, &Graph::terminateCrawlerThreads); - - connect (wc_parser, &WebCrawler_Parser::finished, - this, &Graph::terminateCrawlerThreads); - - connect (wc_spider, &WebCrawler_Spider::parse, - wc_parser, &WebCrawler_Parser::parse ); - - connect (wc_parser, &WebCrawler_Parser::startSpider, - wc_spider, &WebCrawler_Spider::get ); - - - qDebug() << "Graph::webCrawl() Starting parser & spider QThreads!"; - wc_parserThread.start(); - wc_spiderThread.start(); - - qDebug() << "Graph::webCrawl() Creating initial node 1, url: " << seed; - createVertexWebCrawler(seed, 1); - - qDebug() << "Graph::webCrawl() calling spider get() for that url!"; - emit operateSpider(); - - qDebug("Graph::webCrawl() - reach the end - See the threads running? "); -} - - -//called from Graph, when closing network, to terminate all processes -//also called indirectly when wc_spider finishes -void Graph::terminateCrawlerThreads (QString reason){ - qDebug() << "Graph::terminateCrawlerThreads() - reason " << reason; - qDebug() << "Graph::terminateCrawlerThreads() check if wc_parserThread is running..."; - if (wc_parserThread.isRunning() ) { - qDebug() << "Graph::terminateCrawlerThreads() parser thread quit"; - wc_parserThread.quit(); - qDebug() << "Graph::terminateCrawlerThreads() - deleting wc_parser pointer"; - delete wc_parser; - wc_parser = 0; // see why here: https://goo.gl/tQxpGA - - } - qDebug() << "Graph::terminateCrawlerThreads() check if wc_spiderThread is running..."; - if (wc_spiderThread.isRunning() ) { - qDebug() << "Graph::terminateCrawlerThreads() spider thread quit"; - wc_spiderThread.quit(); - qDebug() << "Graph::terminateCrawlerThreads() - deleting wc_spider pointer"; - delete wc_spider; - wc_spider= 0; // see why here: https://goo.gl/tQxpGA - - emit signalNodeSizesByInDegree(true); - } -} /** - Called from filterOrphanNodes via MainWindow to filter nodes with no links - For each orphan Vertex in the Graph, emits the filterVertex() -*/ -void Graph::filterIsolateVertices(bool filterFlag){ - qDebug() << "*** Graph::filterIsolateVertices() " + * @brief Graph::vertexIsolateFilter + * Called from filterOrphanNodes via MainWindow to filter nodes with no links + * For each orphan Vertex in the Graph, emits the filterVertex() + * @param filterFlag + */ +void Graph::vertexIsolateFilter(bool filterFlag){ + qDebug() << "*** Graph::vertexIsolateFilter() " << " setting all isolate nodes to " << filterFlag; QList::const_iterator it; @@ -706,77 +495,43 @@ void Graph::filterIsolateVertices(bool filterFlag){ -/** - Called from filterEdgesDialog via MainWindow - to filter edges over or under a specified weight (m_threshold) - For each Vertex in the Graph, calls the homonymous method of Vertex class. -*/ -void Graph::filterEdgesByWeight(float m_threshold, bool overThreshold){ - if (overThreshold) - qDebug() << "Graph: filterEdgesByWeight() over " << m_threshold ; - else - qDebug() << "Graph: filterEdgesByWeight() below "<< m_threshold ; - - QList::const_iterator it; - for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ - (*it)->filterEdgesByWeight ( m_threshold, overThreshold ); - } - graphModified=true; - emit graphChanged(); - emit statusMessage("Edges have been filtered."); -} - /** - * @brief Graph::filterEdgesByRelation - * Not called by Called from MW to filter out all edges of a given relation - * calls the homonymous method of Vertex class. - * @param relation - */ -void Graph::filterEdgesByRelation(int relation, bool status){ - qDebug() << "Graph::filterEdgesByRelation() " ; - QList::const_iterator it; - for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ - if ( ! (*it)->isEnabled() ) - continue; - (*it)->filterEdgesByRelation ( relation, status ); - } -} - - - -void Graph::slotSetEdgeVisibility ( int relation, int source, int target, bool visible) { - //qDebug() << "Graph: slotSetEdgeVisibility - emitting signal to GW"; - emit setEdgeVisibility ( relation, source, target, visible); -} - - -/** Checks if there is a specific vertex in the graph - Returns the index or -1 - Complexity: O(logN) for index retrieval -*/ -int Graph::hasVertex(long int num){ - qDebug () << "Graph: hasVertex() v: " << num << " with index " << index[num] << " named " << m_graph[ index[num]] ->name(); - if ( m_graph[ index[num]] ->name() == num) - return index[num]; + * @brief Graph::vertexExists + * Checks if there is a specific vertex in the graph. + * Returns the index or -1 + * Complexity: O(logN) for index retrieval + * @param num + * @return + */ +int Graph::vertexExists(const long int &v1){ + qDebug () << "Graph: vertexExists() v: " << v1 + << " with index " << index[v1] + << " named " << m_graph[ index[v1] ] ->name(); + if ( m_graph[ index[v1] ] ->name() == v1) + return index[v1]; else return -1; } -/** Checks if there is a vertex with a specific label in the graph - Returns the index or -1 - Complexity: O(N) -*/ -int Graph::hasVertex(QString label){ - qDebug ()<<"Graph: hasVertex( "<< label.toUtf8() <<" ) ?" ; +/** + * @brief Graph::vertexExists + * Checks if there is a vertex with a specific label in the graph + * Returns the index or -1 + * Complexity: O(N) + * @param label + * @return index or -1 + */ +int Graph::vertexExists(const QString &label){ + qDebug ()<<"Graph: vertexExists() - check for label "<< label.toUtf8() ; QList::const_iterator it; int i=0; for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ if ( (*it) ->label() == label) { -// qDebug()<< "Graph: hasVertex() at pos %i" << i; +// qDebug()<< "Graph: vertexExists() at pos %i" << i; return i; } i++; @@ -787,26 +542,65 @@ int Graph::hasVertex(QString label){ -void Graph::setInitVertexSize (const long int size) { - initVertexSize=size; -} - - -//Changes the size.of vertex v -void Graph::setVertexSize(const long int &v, const int &size) { - m_graph[ index[v] ]->setSize(size); - graphModified=true; +/** + * @brief Graph::vertexPosSet + * Called from MW/GW when node moves to update its position + * @param v1 + * @param x + * @param y + */ +void Graph::vertexPosSet(const int &v1, const int &x, const int &y){ + //qDebug("Graph: vertexPosSet() for %i with index %i with %i, %i", v1, index[v1], x,y); + m_graph[ index[v1] ]->setX( x ); + m_graph[ index[v1] ]->setY( y ); + graphModified=true; +} + + + +/** + * @brief Graph::vertexSizeInit + * Initialization function + * @param size + */ +void Graph::vertexSizeInit (const long int size) { + initVertexSize=size; +} + + + +/** + * @brief Graph::vertexSizeSet + * Changes the size.of vertex v + * Called from MW Node Properties + * @param v + * @param size + */ +void Graph::vertexSizeSet(const long int &v, const int &size) { + m_graph[ index[v] ]->setSize(size); + graphModified=true; emit graphChanged(); emit setNodeSize(v, size); } +/** + * @brief Graph::vertexSize + * @param v + * @return int + */ int Graph::vertexSize(const long &v ) { return m_graph[ index[v] ]-> size(); } -//Changes the size.of all vertices -void Graph::setAllVerticesSize(const int &size) { - setInitVertexSize(size); + +/** + * @brief Graph::vertexSizeAllSet + * Changes the size.of all vertices + * @param size + */ +void Graph::vertexSizeAllSet(const int size) { + qDebug()<< "Graph::vertexSizeAllSet() - new size" << size; + vertexSizeInit(size); QList::const_iterator it; for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ if ( ! (*it)->isEnabled() ){ @@ -822,27 +616,52 @@ void Graph::setAllVerticesSize(const int &size) { } -void Graph::setInitVertexShape(const QString shape) { + +/** + * @brief Graph::vertexShapeInit + * @param shape + */ +void Graph::vertexShapeInit(const QString shape) { initVertexShape=shape; } -//Changes the shape.of vertex v -void Graph::setVertexShape(const int v1, const QString shape){ + + +/** + * @brief Graph::vertexShapeSet + * Changes the shape.of vertex v + * @param v1 + * @param shape + */ +void Graph::vertexShapeSet(const int v1, const QString shape){ m_graph[ index[v1] ]->setShape(shape); - emit setNodeShape( v1, shape); + emit setNodeShape(v1, shape); graphModified=true; emit graphChanged(); } -//returns the shape of this vertex + +/** + * @brief Graph::vertexShape + * Returns the shape of this vertex + * @param v1 + * @return + */ QString Graph::vertexShape(const int &v1){ return m_graph[ index[v1] ]->shape(); } -void Graph::setAllVerticesShape(const QString shape) { - setInitVertexShape(shape); + +/** + * @brief Graph::vertexShapeAllSet + * Changes the shape.of all vertices + * @param shape + */ +void Graph::vertexShapeAllSet(const QString shape) { + qDebug() << "Graph::vertexShapeAllSet - shape " <::const_iterator it; for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ if ( ! (*it)->isEnabled() ){ @@ -858,21 +677,212 @@ void Graph::setAllVerticesShape(const QString shape) { } -//Changes the initial color of vertices numbers -void Graph::setInitVertexNumberColor (QString color) { + + + +/** + * @brief Graph::vertexColorSet + * Changes the color of vertex v1 + * @param v1 + * @param color + */ +void Graph::vertexColorSet(const long int &v1, const QString &color){ + qDebug()<< "Graph: vertexColorSet for "<< v1 << ", index " << index[v1]<< " with color "<< color; + m_graph[ index[v1] ]->setColor ( color ); + emit setNodeColor ( m_graph[ index[v1] ]-> name(), color ); + graphModified=true; + emit graphChanged(); +} + +/** + * @brief Graph::vertexColor + * @param v1 + * @return + */ +QColor Graph::vertexColor(const long int &v1){ + return QColor ( m_graph[ index[v1] ] -> color() ) ; +} + + +/** + * @brief Graph::vertexColorInit + * default vertex color initialization + * @param color + */ +void Graph::vertexColorInit(const QString &color){ + initVertexColor=color; +} + + + +/** + * @brief Graph::vertexColorAllSet + * Changes the color of all vertices and updates default vertex color + * @param color + */ +void Graph::vertexColorAllSet(const QString &color) { + qDebug() << "*** Graph::vertexColorAllSet() " + << " to " << color; + vertexColorInit(color); + QList::const_iterator it; + for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + if ( ! (*it)->isEnabled() ){ + continue; + } + else { + qDebug() << "Graph::vertexColorAllSet() Vertex " << (*it)->name() + << " new color " << color; + (*it)->setColor(color) ; + emit setNodeColor ( (*it)-> name(), color ); + } + } + graphModified=true; + emit graphChanged(); + +} + + + +/** + * @brief Graph::vertexNumberColorInit + * Changes the initial color of vertices numbers + * @param color + */ +void Graph::vertexNumberColorInit (QString color) { initVertexNumberColor = color; } -//Changes the initial size of vertices numbers -void Graph::setInitVertexNumberSize (int size) { + + + +/** + * @brief Graph::vertexNumberSizeInit + * Changes the initial size of vertices numbers + * @param size + */ +void Graph::vertexNumberSizeInit (const int &size) { initVertexNumberSize = size; } -/**Changes the label.of vertex v */ -void Graph::setVertexLabel(int v1, QString label){ - qDebug()<< "Graph: setVertexLabel for "<< v1 << ", index " << index[v1]<< " with label"<< label; +/** + * @brief Graph::vertexNumberSizeSet + * Changes the size.of vertex v number + * @param v + * @param size + */ +void Graph::vertexNumberSizeSet(const long int &v, const int &size) { + m_graph[ index[v] ]->setNumberSize (size); + graphModified=true; + emit graphChanged(); + emit setNodeNumberSize(v, size); +} + + +/** + * @brief Graph::vertexNumberSizeSetAll + * @param size + */ +void Graph::vertexNumberSizeSetAll(const int &size) { + qDebug() << "*** Graph::vertexNumberSizeSetAll() " + << " to " << size; + vertexNumberSizeInit(size); + QList::const_iterator it; + for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + if ( ! (*it)->isEnabled() ){ + continue; + } + else { + qDebug() << "Graph::vertexNumberSizeSetAll() Vertex " << (*it)->name() + << " new size " << size; + (*it)->setNumberSize(size) ; + emit setNodeNumberSize ( (*it)-> name(), size); + } + } + graphModified=true; + emit graphChanged(); +} + + +//Changes the initial distance of vertices numbers +void Graph::vertexNumberDistanceInit(const int &distance) { + initVertexNumberDistance = distance; +} + + +/** + * @brief Graph::vertexNumberDistanceSet + * Changes the distance.of vertex v number from the vertex + * @param v + * @param size + */ +void Graph::vertexNumberDistanceSet(const long int &v, const int &newDistance) { + m_graph[ index[v] ]->setNumberDistance (newDistance); + graphModified=true; + emit graphChanged(); + emit setNodeNumberDistance(v, newDistance); +} + + +/** + * @brief Graph::vertexNumberDistanceSetAll + * Changes the distance.of all vertex number from their vertices + * @param size + */ +void Graph::vertexNumberDistanceSetAll(const int &newDistance) { + qDebug() << "*** Graph::vertexNumberDistanceSetAll() " + << " to " << newDistance; + vertexNumberDistanceInit(newDistance); + QList::const_iterator it; + for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + if ( ! (*it)->isEnabled() ){ + continue; + } + else { + qDebug() << "Graph::vertexNumberDistanceSetAll() Vertex " << (*it)->name() + << " new distance " << newDistance; + (*it)->setNumberDistance(newDistance) ; + emit setNodeNumberDistance ( (*it)-> name(), newDistance); + } + } + graphModified=true; + emit graphChanged(); +} + + + +/** + * @brief Graph::vertexNumbersInsideNodesSet + * @param toggle + */ +void Graph::vertexNumbersInsideNodesSet(bool toggle){ + initNumbersInsideNodes=toggle; + +} + +/** + * @brief Graph::vertexNumbersVisibilitySet + * @param toggle + */ +void Graph::vertexNumbersVisibilitySet(bool toggle){ + initVertexNumbersVisibility=toggle; + +} + + + + + + +/** + * @brief Graph::vertexLabelSet + * Changes the label of a vertex v1 + * @param v1 + * @param label + */ +void Graph::vertexLabelSet(int v1, QString label){ + qDebug()<< "Graph: vertexLabelSet for "<< v1 << ", index " << index[v1]<< " with label"<< label; m_graph[ index[v1] ]->setLabel ( label); emit setNodeLabel ( m_graph[ index[v1] ]-> name(), label); graphModified=true; @@ -881,104 +891,558 @@ void Graph::setVertexLabel(int v1, QString label){ -//Changes the init size of new vertices labels -void Graph::setInitVertexLabelSize(int newSize) { +/** + * @brief Graph::vertexLabel + * Returns the label of a vertex v1 + * @param v1 + * @return + */ +QString Graph::vertexLabel(const long int &v1){ + return m_graph[ index[v1] ]->label (); +} + + +/** + * @brief Graph::vertexLabelsVisibilitySet + * @param toggle + */ +void Graph::vertexLabelsVisibilitySet(bool toggle){ + initVertexLabelsVisibility=toggle; +} + + +/** + * @brief Graph::vertexLabelSizeInit + * Changes the default size of vertex labels + * @param newSize + */ +void Graph::vertexLabelSizeInit(int newSize) { initVertexLabelSize = newSize; } -//Changes the size of a vertex label -void Graph::setVertexLabelSize(int v1, int newSize) { - qDebug()<< "Graph: setVertexLabelSize for "<< v1 << ", index " << index[v1]<< " with size "<< newSize; - m_graph[ index[v1] ] -> setLabelSize ( newSize ); + +/** + * @brief Graph::vertexLabelSizeSet + * Changes the label size of vertex v1 + * @param v1 + * @param size + */ +void Graph::vertexLabelSizeSet(const long int &v1, const int &size) { + qDebug()<< "Graph: vertexLabelSizeSet for "<< v1 << ", index " + << index[v1]<< " with size "<< size; + m_graph[ index[v1] ] -> setLabelSize ( size ); + emit setNodeLabelSize ( v1, size); + graphModified=true; + emit graphChanged(); + +} + + + +/** + * @brief Graph::vertexLabelSizeAllSet + * Changes the label size of all vertices + * @param size + */ +void Graph::vertexLabelSizeAllSet(const int &size) { + qDebug() << "*** Graph::vertexLabelSizeAllSet() " + << " to " << size; + vertexLabelSizeInit(size); + QList::const_iterator it; + for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + if ( ! (*it)->isEnabled() ){ + continue; + } + else { + qDebug() << "Graph::vertexLabelSizeAllSet() Vertex " << (*it)->name() + << " new size " << size; + (*it)->setLabelSize(size) ; + emit setNodeLabelSize ( (*it)-> name(), size); + } + } + graphModified=true; + emit graphChanged(); +} + + +/** + * @brief Graph::vertexLabelColorSet + * Changes the label color of vertex v1 + * @param v1 + * @param color + */ +void Graph::vertexLabelColorSet(int v1, QString color){ + m_graph[ index[v1] ]->setLabelColor(color); + graphModified=true; + emit graphChanged(); +} + + +/** + * @brief Graph::vertexLabelColorInit + * Changes the default vertex label color + * @param color + */ +void Graph::vertexLabelColorInit(QString color){ + initVertexLabelColor=color; +} + + + + +/** + * @brief Graph::vertexLabelDistanceSet + * Changes the distance.of vertex v label from the vertex + * @param v + * @param size + */ +void Graph::vertexLabelDistanceSet(const long int &v, const int &newDistance) { + m_graph[ index[v] ]->setLabelDistance (newDistance); + graphModified=true; + emit graphChanged(); + emit setNodeLabelDistance(v, newDistance); +} + + +/** + * @brief Graph::vertexLabelDistanceAllSet + * Changes the distance.of all vertex labels from their vertices + * @param size + */ +void Graph::vertexLabelDistanceAllSet(const int &newDistance) { + qDebug() << "*** Graph::vertexLabelDistanceAllSet() " + << " to " << newDistance; + vertexLabelDistanceInit(newDistance); + QList::const_iterator it; + for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + if ( ! (*it)->isEnabled() ){ + continue; + } + else { + qDebug() << "Graph::vertexLabelDistanceAllSet() Vertex " << (*it)->name() + << " new size " << newDistance; + (*it)->setLabelDistance(newDistance) ; + emit setNodeLabelDistance ( (*it)-> name(), newDistance); + } + } graphModified=true; emit graphChanged(); +} + + + + +/** + * @brief Graph::vertexLabelDistanceInit + * Changes the default distance of vertex labels + * @param distance + */ +void Graph::vertexLabelDistanceInit(const int &distance) { + initVertexLabelDistance = distance; +} + + + + + + + + +/** + * @brief Graph::edgeCreate + * Checks if edge exists, and if the opposite edge exists + * Calls edgeAdd to add the new edge to the Graph, + * then emits drawEdge() which calls GraphicsWidget::drawEdge() to draw the new edge. + * Called from homonymous signal of Parser class. + * Also called from MW when user clicks on the "add link" button + * Also called (via MW) from GW when user middle-clicks on two nodes. + * @param v1 + * @param v2 + * @param weight + * @param color + * @param reciprocal + * @param drawArrows + * @param bezier + */ +void Graph::edgeCreate(const int &v1, const int &v2, const float &weight, + const QString &color, + const int &type, + const bool &drawArrows, const bool &bezier, + const QString &label, const bool &signalMW){ + qDebug() <<"-- Graph::edgeCreate() - " << v1 << " -> " << v2 + << " weight " << weight + << " type " << type + << " label " << label; + // check whether there is already such an edge + // (see #713617 - https://bugs.launchpad.net/socnetv/+bug/713617) + if (!edgeExists(v1,v2)){ + if ( type == EDGE_RECIPROCAL_UNDIRECTED ) { + qDebug()<< "-- Graph::edgeCreate() - " + << "Creating RECIPROCAL edge - emitting drawEdge signal to GW"; + edgeAdd ( v1, v2, weight, type, label, color ); + emit drawEdge(v1, v2, weight, label, color, type, + drawArrows, bezier, initEdgeWeightNumbers); + } + else if ( edgeExists( v2, v1) ) { + qDebug()<<"-- Graph::edgeCreate() - Opposite arc exists. " + << " Emitting drawEdge to GW "; + edgeAdd ( v1, v2, weight, EDGE_DIRECTED_OPPOSITE_EXISTS , label, color); + emit drawEdge(v1, v2, weight, label, color, EDGE_DIRECTED_OPPOSITE_EXISTS, + drawArrows, bezier, initEdgeWeightNumbers); + m_undirected = false; + } + else { + qDebug()<< "-- Graph::edgeCreate() - " + << "Opposite arc does not exist. Emitting drawEdge to GW..."; + edgeAdd ( v1, v2, weight, EDGE_DIRECTED, label, color ); + emit drawEdge(v1, v2, weight, label, color, EDGE_DIRECTED, + drawArrows, bezier, initEdgeWeightNumbers); + m_undirected = false; + } + } + else { + qDebug() << "-- Graph::edgeCreate() - " + << "Edge " << v1 << " -> " << v2 + << " declared previously (exists) - nothing to do \n\n"; + } + //draw new edges the same color with those of the file loaded, + // on user clicks on the canvas + initEdgeColor=color; + + + if (signalMW) + emit graphChanged(); + +} + + + + + +/** + * @brief Graph::edgeCreateWebCrawler + * Called from WebCrawler when it finds an new link + * Calls edgeCreate() method with initEdgeColor + * @param source + * @param target + */ +void Graph::edgeCreateWebCrawler (const int &source, const int &target){ + qDebug()<< " Graph::edgeCreateWebCrawler() - from " << source << " to " << target ; + float weight = 1.0; + bool drawArrows=true; + bool bezier=false; + + edgeCreate(source, target, weight, initEdgeColor, EDGE_DIRECTED, drawArrows, bezier); +} + + + + +/** + * @brief Graph::edgeAdd + * Adds an edge between v1 and v2 + * @param v1 + * @param v2 + * @param weight + * @param label + * @param color + * @param type + */ +void Graph::edgeAdd (const int &v1, const int &v2, const float &weight, + const int &type, + const QString &label, + const QString &color) { + + int source=index[v1]; + int target=index[v2]; + + qDebug()<< "Graph: edgeAdd() from vertex "<< v1 << "["<< source + << "] to vertex "<< v2 << "["<< target << "] of weight "<edgeAddTo(v2, weight ); + m_graph [ target ]->edgeAddFrom(v1, weight); + m_graph[ source ]->setOutLinkColor(v2, color); + m_graph[ source ]->setOutEdgeLabel(v2, label); + + if (type == EDGE_DIRECTED_OPPOSITE_EXISTS ){ + // make existing opposite edge reciprocal + + } + else if (type == EDGE_RECIPROCAL_UNDIRECTED){ + //create opposite edge and declare both reciprocal. + m_graph [ target ]->edgeAddTo(v1, weight ); + m_graph [ source ]->edgeAddFrom(target, weight); + } + graphModified=true; +} + + + + + + +/** + * @brief Graph::edgeRemove + * Removes the edge (arc) between v1 and v2 + * @param v1 + * @param v2 + * @param undirected if true it also removes the opposite edge + */ +void Graph::edgeRemove (const long int &v1, const long int &v2, const bool &undirected) { + qDebug ()<< "Graph::edgeRemove() - edge " << v1 << " index " << index[v1] + << " ->" << v2 << " to be removed from graph"; + m_graph [ index[v1] ]->edgeRemoveTo(v2); + m_graph [ index[v2] ]->edgeRemoveFrom(v1); + + if ( edgeExists(v2,v1) !=0) { + symmetricAdjacencyMatrix=false; + if (undirected) { // remove opposite edge + m_graph [ index[v2] ]->edgeRemoveTo(v1); + m_graph [ index[v1] ]->edgeRemoveFrom(v2); + symmetricAdjacencyMatrix=true; + } + } + + graphModified=true; + + emit eraseEdge(v1,v2); + emit graphChanged(); +} + + + + +/** + * @brief Graph::edgeVisibilitySet + * Changes the canvas visibility of an edge + * Called from Vertex when edgeFilterByWeight is called + * @param relation + * @param source + * @param target + * @param visible + */ +void Graph::edgeVisibilitySet ( int relation, int source, int target, bool visible) { + //qDebug() << "Graph: edgeVisibilitySet - emitting signal to GW"; + emit setEdgeVisibility ( relation, source, target, visible); +} + + + + + + +/** + * @brief Graph::edgeFilterByWeight + * Called from MW::DialogEdgeFilter to filter edges over or under + * a specified weight (m_threshold). + * For each Vertex in the Graph, calls the homonymous method of Vertex class. + * @param m_threshold + * @param overThreshold + */ +void Graph::edgeFilterByWeight(float m_threshold, bool overThreshold){ + if (overThreshold) + qDebug() << "Graph: edgeFilterByWeight() over " << m_threshold ; + else + qDebug() << "Graph: edgeFilterByWeight() below "<< m_threshold ; + + QList::const_iterator it; + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + (*it)->edgeFilterByWeight ( m_threshold, overThreshold ); + } + graphModified=true; + emit graphChanged(); + emit statusMessage("Edges have been filtered."); +} + + + +/** + * @brief Graph::edgeFilterByRelation + * Filter out all edges of a given relation + * Calls the homonymous method of Vertex class. + * @param relation + */ +void Graph::edgeFilterByRelation(int relation, bool status){ + qDebug() << "Graph::edgeFilterByRelation() " ; + QList::const_iterator it; + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + if ( ! (*it)->isEnabled() ) + continue; + (*it)->edgeFilterByRelation ( relation, status ); + } +} + + + + +/** + * @brief Graph::edgeExists + * Checks if there is a directed edge (arc) from v1 to v2 + Complexity: O(logN) for index retrieval + O(1) for QList index retrieval + O(logN) for checking edge(v2) + * @param v1 + * @param v2 + * @param undirected if true, check if there is an undirected edge v1<->v2 + * @return zero if arc does not exist or non-zero if arc exists + */ +float Graph::edgeExists (const long int &v1, const long int &v2, const bool &undirected) { + //qDebug() << "Graph::edgeExists() " << v1 << " -> " << v2 << " ? " ; + if (!undirected) + return m_graph[ index[v1] ]->hasEdgeTo(v2); + else { //undirected + edgeWeightTemp = 0; + edgeWeightTemp = m_graph[ index[v1] ]->hasEdgeTo(v2); + if ( edgeWeightTemp!=0 && + ( edgeWeightTemp == m_graph[ index[v2] ]->hasEdgeTo(v1) ) ) + return edgeWeightTemp; + } + return 0; +} + + + + +/** + * @brief Graph::edgeSymmetric + * Returns TRUE if (v1, v2) is symmetric. + * @param v1 + * @param v2 + * @return + */ +bool Graph::edgeSymmetric(const long int &v1, const long int &v2){ + qDebug("***Graph: edgeSymmetric()"); + if ( ( edgeExists( v1, v2 , true) ) !=0 ) { + return true; + } + else { + return false; + } + +} + + +/** + * @brief Graph::edgesEnabled + * Returns |E| of graph - only the enabled edges + * @return + */ +int Graph::edgesEnabled() { + + int recountedEdges=0; + QList::const_iterator it; + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + recountedEdges+=(*it)->outEdges(); + } + qDebug() << "Graph::edgesEnabled() - edges recounted: " << recountedEdges; + return (isUndirected()) ? recountedEdges / 2 : recountedEdges; } -//Changes the shape.of vertex v -void Graph::setVertexLabelColor(int v1, QString color){ - m_graph[ index[v1] ]->setLabelColor(color); - graphModified=true; - emit graphChanged(); + +/** + * @brief Graph::edgesOutbound + * *Returns the number of outbound edges (arcs) from vertex v1 + * @param v1 + * @return + */ +int Graph::edgesOutbound(int v1) { + qDebug("Graph: edgesOutbound()"); + return m_graph[ index[v1] ]->outEdges(); } -void Graph::setInitVertexLabelColor(QString color){ - initVertexLabelColor=color; +/** + * @brief Graph::edgesInbound + * Returns the number of inbound edges (arcs) to vertex v1 + * @param v1 + * @return int + */ +int Graph::edgesInbound (int v1) { + qDebug("Graph: edgesInbound()"); + return m_graph[ index[v1] ]->inEdges(); } -QString Graph::vertexLabel(const long int &v1){ - return m_graph[ index[v1] ]->label (); -} /** - Changes the color of vertex v1 -*/ -void Graph::setVertexColor(const long int &v1, const QString &color){ - qDebug()<< "Graph: setVertexColor for "<< v1 << ", index " << index[v1]<< " with color "<< color; - m_graph[ index[v1] ]->setColor ( color ); - emit setNodeColor ( m_graph[ index[v1] ]-> name(), color ); + * @brief Graph::edgeWeightSet + * Changes the weight of an edge (arc) between v1 and v2 + * @param v1 + * @param v2 + * @param weight + */ +void Graph::edgeWeightSet (const long &v1, const long &v2, + const float &weight, const bool &undirected) { + qDebug() << "Graph::edgeWeightSet() - " << v1 << "[" << index[v1] + << "] ->" << v2 << "[" << index[v2] << "]" << " = " << weight; + m_graph [ index[v1] ]->changeOutEdgeWeight(v2, weight); + if (undirected) { + qDebug() << "Graph::edgeWeightSet() - changing opposite edge weight too"; + m_graph [ index[v2] ]->changeOutEdgeWeight(v1, weight); + } graphModified=true; + emit setEdgeWeight(v1,v2, weight); emit graphChanged(); -} -QColor Graph::vertexColor(const long int &v1){ - return QColor ( m_graph[ index[v1] ] -> color() ) ; } -void Graph::setInitVertexColor(const QString &color){ - initVertexColor=color; + + + + +/** + * @brief Graph::edgeWeight + * Returns the color qstring of the directed edge v1 -> v2 + * @param v1 + * @param v2 + * @return + */ +float Graph::edgeWeight (const long &v1, const long &v2) const{ + return m_graph[ index[v1] ]->hasEdgeTo(v2); } -void Graph::setAllVerticesColor(const QString &color) { - qDebug() << "*** Graph::setAllVerticesColor() " - << " to " << color; - setInitVertexColor(color); - QList::const_iterator it; - for ( it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ - if ( ! (*it)->isEnabled() ){ - continue; - } - else { - qDebug() << "Graph::setAllVerticesColor() Vertex " << (*it)->name() - << " new color " << color; - (*it)->setColor(color) ; - emit setNodeColor ( (*it)-> name(), color ); - } - } - graphModified=true; - emit graphChanged(); + +/** + * @brief Graph::edgeWeightNumbersVisibilitySet + * Changes the visibility of edge weight numbers + * @param toggle + */ +void Graph::edgeWeightNumbersVisibilitySet (const bool &toggle) { + initEdgeWeightNumbers = toggle; } -void Graph::setInitEdgeColor(const QString &color){ +/** + * @brief Graph::edgeColorInit + * Saves the default edge color + * Used by random network creation methods + * @param color + */ +void Graph::edgeColorInit(const QString &color){ initEdgeColor=color; } -//Returns the edgeColor -QString Graph::edgeColor (const long &v1, const long &v2){ - return m_graph[ index[v1] ]->outLinkColor(v2); -} - /** - Changes the color of all edges. -*/ -bool Graph::setAllEdgesColor(const QString &color){ - qDebug()<< "\n\nGraph::setAllEdgesColor()" << color; + * @brief Graph::edgeColorAllSet + * Changes the color of all edges. + * @param color + * @return + */ +bool Graph::edgeColorAllSet(const QString &color, const int &threshold){ + qDebug()<< "Graph::edgeColorAllSet() - new color: " << color; int target=0, source=0; - setInitEdgeColor(color); + edgeColorInit(color); QHash *enabledOutEdges = new QHash; QHash::const_iterator it1; QList::const_iterator it; @@ -991,10 +1455,22 @@ bool Graph::setAllEdgesColor(const QString &color){ it1=enabledOutEdges->cbegin(); while ( it1!=enabledOutEdges->cend() ){ target = it1.key(); -// qDebug() << "=== Graph::setAllEdgesColor() : " -// << source << "->" << target << " new color " << color; - (*it)->setOutLinkColor(target, color); - emit changeEdgeColor(source, target, color); + if (threshold != RAND_MAX ) { + if ( it1.value() < threshold ) { + qDebug() << " Graph::edgeColorAllSet() below weight threshold " + << threshold << " - edge " + << source << "->" << target << " new color " << color; + (*it)->setOutLinkColor(target, color); + emit setEdgeColor(source, target, color); + } + } + else { + qDebug() << " Graph::edgeColorAllSet() : " + << source << "->" << target << " new color " << color; + (*it)->setOutLinkColor(target, color); + emit setEdgeColor(source, target, color); + + } ++it1; } } @@ -1006,18 +1482,24 @@ bool Graph::setAllEdgesColor(const QString &color){ } + + /** - Changes the color of edge (s,t). -*/ -void Graph::setEdgeColor(const long &v1, const long &v2, const QString &color){ - qDebug()<< "Graph::setEdgeColor() - "<< v1 << " -> "<< v2 + * @brief Graph::edgeColorSet + * Changes the color of edge s -> t + * @param v1 + * @param v2 + * @param color + */ +void Graph::edgeColorSet(const long &v1, const long &v2, const QString &color){ + qDebug()<< "Graph::edgeColorSet() - "<< v1 << " -> "<< v2 <<" index ("<< index[v1]<< " -> "<setOutLinkColor(v2, color); - emit changeEdgeColor(v1, v2, color); + emit setEdgeColor(v1, v2, color); if (isSymmetric()) { m_graph[ index[v2] ]->setOutLinkColor(v1, color); - emit changeEdgeColor(v2, v1, color); + emit setEdgeColor(v2, v1, color); } graphModified=true; emit graphChanged(); @@ -1026,138 +1508,95 @@ void Graph::setEdgeColor(const long &v1, const long &v2, const QString &color){ -/** Checks if there is a directed edge (arc) from v1 to v2 - Complexity: O(logN) for index retrieval + O(1) for QList index retrieval + O(logN) for checking edge(v2) -*/ -float Graph::hasArc (const long int &v1, const long int &v2) { - //qDebug() << "Graph::hasArc() " << v1 << " -> " << v2 << " ? " ; - return m_graph[ index[v1] ]->hasEdgeTo(v2); -} - -/** Checks if there is a edge between v1 and v2 (both arcs exist) -*/ -bool Graph::hasEdge (const int &v1, const long &v2) { - qDebug() << "Graph::hasEdge() " << v1 << " <-> " << v2 << " ? " ; - return ( ( m_graph[ index[v1] ]->hasEdgeTo(v2) != 0 ) - && ( m_graph[ index[v2] ]->hasEdgeTo(v1) != 0) ) ? true: false; -} - - - /** - Returns |E| of graph -*/ -int Graph::enabledEdges() { - - int recountedEdges=0; - QList::const_iterator it; - for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ - recountedEdges+=(*it)->outEdges(); - } - qDebug() << "Graph::enabledEdges() - edges recounted: " << recountedEdges; - - return recountedEdges; + * @brief Graph::edgeColor + * Returns the color qstring of the directed edge v1 -> v2 + * @param v1 + * @param v2 + * @return + */ +QString Graph::edgeColor (const long &v1, const long &v2){ + return m_graph[ index[v1] ]->outLinkColor(v2); } -void Graph::edges(){ - H_edges::const_iterator it1; - QList::const_iterator it; - int relation=0,source=0, target=0, w=0; - float weight=0; Q_UNUSED(weight); - bool edgeStatus=false; - - for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it) { - if ( ! (*it)->isEnabled() ) - continue ; - source = index[ (*it)->name() ]; - it1=m_graph [ source ] ->m_outEdges.cbegin(); - while ( it1!=m_graph [ source ] -> m_outEdges.cend() ){ - relation = it1.value().first; - if ( relation != currentRelation() ) { - ++it1; - continue; - } - edgeStatus=it1.value().second.second; - if ( edgeStatus != true) { - ++it1; - continue; - } - target = it1.key(); - w=index[ target ]; - weight = it1.value().second.first; - qDebug("u=%i is connected with node %i of index w=%i. ", source, target, w); - ++it1; - } - } -} /** - Called from MainWindow -*/ -void Graph::updateVertCoords(int v1, int x, int y){ - //qDebug("Graph: updateVertCoords() for %i with index %i with %i, %i", v1, index[v1], x,y); - m_graph[ index[v1] ]->setX( x ); - m_graph[ index[v1] ]->setY( y ); + * @brief Graph::edgeLabelSet + * Changes the label of edge v1 -> v2 + * @param v1 + * @param v2 + * @param weight + */ +void Graph::edgeLabelSet (const long &v1, const long &v2, const QString &label) { + qDebug() << "Graph::edgeLabelSet() " << v1 << "[" << index[v1] + << "] -> " << v2 << "[" << index[v2] << "]" << " label " << label; + m_graph[ index[v1] ]->setOutEdgeLabel(v2, label); graphModified=true; -} - + emit setEdgeLabel(v1,v2, label); + emit graphChanged(); +} /** - * @brief Graph::outboundEdges - * *Returns the number of outbound edges (arcs) from vertex v1 + * @brief Graph::edgeLabel + * Returns the label of edge v1->v2 * @param v1 + * @param v2 * @return */ -int Graph::outboundEdges(int v1) { - qDebug("Graph: outboundEdges()"); - return m_graph[ index[v1] ]->outEdges(); +QString Graph::edgeLabel (const long int &v1, const long int &v2) const { + return m_graph [ index[v1] ]->outEdgeLabel(v2); } /** - * @brief Graph::inboundEdges - * Returns the number of inbound edges (arcs) to vertex v1 - * @param v1 - * @return int + * @brief Graph::edgeLabelsVisibilitySet + * @param toggle */ -int Graph::inboundEdges (int v1) { - qDebug("Graph: inboundEdges()"); - return m_graph[ index[v1] ]->inEdges(); +void Graph::edgeLabelsVisibilitySet (const bool &toggle) { + initEdgeLabels = toggle; } - /** - * @brief Graph::outDegree - * Returns the outDegree (sum of outEdges weights) of vertex v1 + * @brief Graph::vertexDegreeOut + * Returns the outDegree (sum of outbound edge weights) of vertex v1 * @param v1 * @return */ -int Graph::outDegree (int v1) { - qDebug("Graph: outDegree()"); - return m_graph[ index[v1] ]->outDegree(); +int Graph::vertexDegreeOut (int v1) { + qDebug("Graph: vertexDegreeOut()"); + return m_graph[ index[v1] ]->degreeOut(); } + /** - Returns the inDegree (sum of inEdges weights) of vertex v1 -*/ -int Graph::inDegree (int v1) { - qDebug("Graph: inDegree()"); - return m_graph[ index[v1] ]-> inDegree(); + * @brief Graph::vertexDegreeIn + * Returns the inDegree (sum of inbound edge weights) of vertex v1 + * @param v1 + * @return + */ +int Graph::vertexDegreeIn (int v1) { + qDebug("Graph: vertexDegreeIn()"); + return m_graph[ index[v1] ]-> degreeIn(); } -/** - Returns |V| of graph -*/ + +/** + * @brief Graph::vertices + * Returns |V| of graph + * @param dropIsolates + * @param countAll + * @return + */ int Graph::vertices(const bool dropIsolates, const bool countAll) { qDebug("Graph: vertices()"); m_totalVertices=0; @@ -1175,9 +1614,13 @@ int Graph::vertices(const bool dropIsolates, const bool countAll) { return m_totalVertices; } + + /** - Returns a list of all isolated vertices inside the graph -*/ + * @brief Graph::verticesIsolated + * Returns a list of all isolated vertices inside the graph + * @return + */ QList Graph::verticesIsolated(){ qDebug()<< "Graph::verticesIsolated()"; if (!graphModified){ @@ -1198,45 +1641,54 @@ QList Graph::verticesIsolated(){ } + /** + * @brief Graph::density * Returns ratio of present edges to total possible edges. + * @return */ float Graph::density() { - qDebug("Graph: density()"); + qDebug()<< "Graph: density()"; int vert=vertices(); if (vert!=0 && vert!=1) - return (float) enabledEdges() / (float)(vert*(vert-1.0)); + return (isUndirected()) ? + (float) 2* edgesEnabled() / (float)(vert*(vert-1.0)) : + (float) edgesEnabled() / (float)(vert*(vert-1.0)) ; else return 0; } + /** + * @brief Graph::isWeighted * Checks if the graph is weighted, i.e. if any e in |E| has value > 1 - * O(n^2) + * Complexity: O(n^2) + * @return */ bool Graph::isWeighted(){ - qDebug("Graph: isWeighted()"); QList::const_iterator it, it1; for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ for (it1=m_graph.cbegin(); it1!=m_graph.cend(); ++it1){ - if ( ( this->hasArc ( (*it1)->name(), (*it)->name() ) ) > 1 ) { + if ( ( edgeExists ( (*it1)->name(), (*it)->name() ) ) > 1 ) { + //FIXME What about negative weights?? or 0 < w < 1 ? return true; } } } + qDebug()<< "Graph: isWeighted() - false"; return false; } /** - Returns the sum of vertices having outboundEdges + Returns the sum of vertices having edgesOutbound */ int Graph::verticesWithOutboundEdges(){ return outboundEdgesVert; } /** - Returns the sum of vertices having inboundEdges + Returns the sum of vertices having edgesInbound */ int Graph::verticesWithInboundEdges(){ return inboundEdgesVert; @@ -1305,45 +1757,149 @@ void Graph::clear() { } - m_isolatedVerticesList.clear(); - disconnectedVertices.clear(); - unilaterallyConnectedVertices.clear(); - influenceDomains.clear(); - influenceRanges.clear(); - triadTypeFreqs.clear(); + m_isolatedVerticesList.clear(); + disconnectedVertices.clear(); + unilaterallyConnectedVertices.clear(); + influenceDomains.clear(); + influenceRanges.clear(); + triadTypeFreqs.clear(); + + m_totalVertices=0; + outboundEdgesVert=0; + inboundEdgesVert=0; + reciprocalEdgesVert=0; + + order=true; //returns true if the indexes of the list is ordered. + m_undirected=false; + calculatedDP=false; + calculatedDC=false; + calculatedIC=false; + calculatedCentralities=false; + calculatedIRCC=false; + calculatedPP=false; + calculatedPRP=false; + calculatedTriad=false; + adjacencyMatrixCreated=false; + reachabilityMatrixCreated=false; + graphModified=false; + symmetricAdjacencyMatrix=true; + + qDebug ()<< "Graph::clear() -Do parser threads run ?"; + terminateParserThreads("Graph::initNet()"); + + qDebug ()<< "Graph::clear() -Do web crawler threads run ?"; + webCrawlTerminateThreads("Graph::initNet"); + + + qDebug("Graph: m_graph cleared. Now reports size %i", m_graph.size()); +} + + + + + +//called from Graph, when closing network, to terminate all processes +//also called indirectly when wc_spider finishes +void Graph::webCrawlTerminateThreads (QString reason){ + qDebug() << "Graph::webCrawlTerminateThreads() - reason " << reason; + qDebug() << "Graph::webCrawlTerminateThreads() check if wc_parserThread is running..."; + if (wc_parserThread.isRunning() ) { + qDebug() << "Graph::webCrawlTerminateThreads() parser thread quit"; + wc_parserThread.quit(); + qDebug() << "Graph::webCrawlTerminateThreads() - deleting wc_parser pointer"; + delete wc_parser; + wc_parser = 0; // see why here: https://goo.gl/tQxpGA + + } + qDebug() << "Graph::webCrawlTerminateThreads() check if wc_spiderThread is running..."; + if (wc_spiderThread.isRunning() ) { + qDebug() << "Graph::webCrawlTerminateThreads() spider thread quit"; + wc_spiderThread.quit(); + qDebug() << "Graph::webCrawlTerminateThreads() - deleting wc_spider pointer"; + delete wc_spider; + wc_spider= 0; // see why here: https://goo.gl/tQxpGA + + emit signalNodeSizesByInDegree(true); + } + +} + + + + + +//Called by MW to start a web crawler... +void Graph::webCrawl( QString seed, int maxNodes, int maxRecursion, + bool extLinks, bool intLinks){ + + qDebug() << "Graph::webCrawl() - seed " << seed ; + //WebCrawler *crawler = new WebCrawler; + + qDebug() << "Graph::webCrawl() Creating wc_spider & wc_parser objects"; + WebCrawler_Parser *wc_parser = new WebCrawler_Parser(seed, maxNodes, + maxRecursion, + extLinks, + intLinks); + WebCrawler_Spider *wc_spider = new WebCrawler_Spider (seed, maxNodes, + maxRecursion, + extLinks, intLinks); + + qDebug() << "Graph::webCrawl() Moving parser & spider to new QThreads!"; + qDebug () << " graph thread " << this->thread(); + qDebug () << " wc_parser thread " << wc_parser->thread(); + qDebug () << " wc_spider thread " << wc_spider->thread(); + wc_parser->moveToThread(&wc_parserThread); + wc_spider->moveToThread(&wc_spiderThread); + qDebug () << " graph thread is " << this->thread(); + qDebug () << " wc_parser thread now " << wc_parser->thread(); + qDebug () << " wc_spider thread now " << wc_spider->thread(); + + + qDebug() << "Graph::webCrawl() Connecting signals from/to parser & spider"; + connect(&wc_parserThread, &QThread::finished, + wc_parser, &QObject::deleteLater); - m_totalVertices=0; - outboundEdgesVert=0; - inboundEdgesVert=0; - reciprocalEdgesVert=0; + connect(&wc_spiderThread, &QThread::finished, + wc_spider, &QObject::deleteLater); - order=true; //returns true if the indexes of the list is ordered. - m_undirected=false; - calculatedDP=false; - calculatedDC=false; - calculatedIC=false; - calculatedCentralities=false; - calculatedIRCC=false; - calculatedPP=false; - calculatedPRP=false; - calculatedTriad=false; - adjacencyMatrixCreated=false; - reachabilityMatrixCreated=false; - graphModified=false; - symmetricAdjacencyMatrix=true; + connect(this, &Graph::operateSpider, + wc_spider, &WebCrawler_Spider::get); - qDebug ()<< "Graph::clear() -Do parser threads run ?"; - terminateParserThreads("Graph::initNet()"); + connect(wc_parser, &WebCrawler_Parser::signalCreateNode, + this, &Graph::vertexCreateWebCrawler); - qDebug ()<< "Graph::clear() -Do web crawler threads run ?"; - terminateCrawlerThreads("Graph::initNet"); + connect(wc_parser, &WebCrawler_Parser::signalCreateEdge, + this, &Graph::edgeCreateWebCrawler); + connect (wc_spider, &WebCrawler_Spider::finished, + this, &Graph::webCrawlTerminateThreads); - qDebug("Graph: m_graph cleared. Now reports size %i", m_graph.size()); + connect (wc_parser, &WebCrawler_Parser::finished, + this, &Graph::webCrawlTerminateThreads); + + connect (wc_spider, &WebCrawler_Spider::parse, + wc_parser, &WebCrawler_Parser::parse ); + + connect (wc_parser, &WebCrawler_Parser::startSpider, + wc_spider, &WebCrawler_Spider::get ); + + + qDebug() << "Graph::webCrawl() Starting parser & spider QThreads!"; + wc_parserThread.start(); + wc_spiderThread.start(); + + qDebug() << "Graph::webCrawl() Creating initial node 1, url: " << seed; + vertexCreateWebCrawler(seed, 1); + + qDebug() << "Graph::webCrawl() calling spider get() for that url!"; + emit operateSpider(); + + qDebug("Graph::webCrawl() - reach the end - See the threads running? "); } + /** * @brief Graph::isSymmetric * Returns TRUE if the adjacency matrix of the current relation is symmetric @@ -1399,13 +1955,16 @@ bool Graph::isSymmetric(){ + /** -* Transform the digraph to undirected graph (all edges reciprocal) -*/ + * @brief Graph::symmetrize + * Transforms the graph to symmetric (all edges reciprocal) + */ void Graph::symmetrize(){ qDebug("Graph: symmetrize"); QList::const_iterator it; int y=0, v2=0, v1=0, weight; + float invertWeight=0; QHash *enabledOutEdges = new QHash; QHash::const_iterator it1; for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ @@ -1420,14 +1979,20 @@ void Graph::symmetrize(){ qDebug() << "Graph:symmetrize() - " << " v1 " << v1 << " outLinked to " << v2 << " weight " << weight; - if ( m_graph[y]->hasEdgeTo( v1 ) == 0 ) { + invertWeight = m_graph[y]->hasEdgeTo( v1 ) ; + if ( invertWeight == 0 ) { qDebug() << "Graph:symmetrize(): s = " << v1 << " is NOT inLinked from y = " << v2 ; - createEdge( v2, v1, weight, initEdgeColor, false, true, false); + edgeCreate( v2, v1, weight, initEdgeColor, false, true, false, + QString::null, false); } - else + else { qDebug() << "Graph: symmetrize(): v1 = " << v1 << " is already inLinked from v2 = " << v2 ; + if (weight!= invertWeight ) + edgeWeightSet(v2,v1,weight); + } + ++it1; } } @@ -1438,46 +2003,116 @@ void Graph::symmetrize(){ } -//Returns TRUE if (v1, v2) is symmetric. -bool Graph::symmetricEdge(int v1, int v2){ - qDebug("***Graph: symmetricEdge()"); - if ( (this->hasArc ( v1, v2 ) ) > 0 && (this->hasArc ( v2, v1 ) ) > 0 ) { -// qDebug("Graph: symmetricEdge: YES"); - return true; + +/** + * @brief Graph::undirected + * Transforms the graph to undirected + */ +void Graph::undirectedSet(const bool &toggle){ + qDebug() << "Graph::undirectedSet()"; + if (!toggle) { + m_undirected=false; + emit graphChanged(); + return; } - else { -// qDebug("Graph: symmetricEdge: NO"); - return false; + QList::const_iterator it; + int v2=0, v1=0, weight; + QHash *enabledOutEdges = new QHash; + QHash::const_iterator it1; + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + v1 = (*it)->name(); + qDebug() << "Graph::undirectedSet() - iterate over edges of v1 " << v1; + enabledOutEdges=(*it)->returnEnabledOutEdges(); + it1=enabledOutEdges->cbegin(); + while ( it1!=enabledOutEdges->cend() ){ + v2 = it1.key(); + weight = it1.value(); + + qDebug() << "Graph::undirectedSet() - " + << " v1 " << v1 + << " -> " << v2 << " = " + << " weight " << weight; + edgeUndirectedSet(v1,v2, weight); + ++it1; + } } + delete enabledOutEdges; + graphModified=true; + symmetricAdjacencyMatrix=m_undirected=true; + emit graphChanged(); +} + +bool Graph::isUndirected() { + return m_undirected; } +/** + * @brief Graph::edgeUndirectedSet + * Tranforms an edge to undirected + * Emits setEdgeUndirected to GW + * @param v1 + * @param v2 + * @param weight + */ +void Graph::edgeUndirectedSet(const long int &v1, const long int &v2, + const float &weight) { + qDebug() << "Graph::edgeUndirectedSet(): " << v1 + << " -> " << v2 ; + int y=index[ v2 ]; + float invertWeight = m_graph[y]->hasEdgeTo( v1 ) ; + if ( invertWeight == 0 ) { + qDebug() << "Graph::edgeUndirectedSet(): opposite " << v1 + << " <- " << v2 << " does not exist - Add it to Graph." ; + edgeAdd(v2,v1, weight, EDGE_DIRECTED_OPPOSITE_EXISTS, "", initEdgeColor); + } + else { + qDebug() << "Graph::edgeUndirectedSet(): opposite " << v1 + << " <- " << v2 << " exists - Checking if edge weights not equal." ; + if (weight!= invertWeight ) + edgeWeightSet(v2,v1,weight); + } + emit setEdgeUndirected(v1, v2, weight); + graphModified=true; + m_undirected = true; +} /** -* Returns the distance between nodes numbered (i-1) and (j-1) -*/ + * @brief Graph::distance + * Returns the distance between nodes numbered (i-1) and (j-1) + * @param i + * @param j + * @param considerWeights + * @param inverseWeights + * @return + */ int Graph::distance(const int i, const int j, const bool considerWeights, const bool inverseWeights){ if ( !distanceMatrixCreated || graphModified ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(false, considerWeights, inverseWeights, false); + distanceMatrixCreate(false, considerWeights, inverseWeights, false); } return DM.item(index[i],index[j]); } + /** -* Returns the diameter of the graph, aka the largest geodesic distance between any two vertices -*/ + * @brief Graph::diameter + * Returns the diameter of the graph, aka the largest geodesic distance between any two vertices + * @param considerWeights + * @param inverseWeights + * @return + */ int Graph::diameter(const bool considerWeights, const bool inverseWeights){ if ( !distanceMatrixCreated || graphModified ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(false, considerWeights, inverseWeights, false); + distanceMatrixCreate(false, considerWeights, inverseWeights, false); } return graphDiameter; } @@ -1485,14 +2120,19 @@ int Graph::diameter(const bool considerWeights, /** -* Returns the average distance of the graph -*/ -float Graph::averageGraphDistance(const bool considerWeights, + * @brief Graph::distanceGraphAverage + * Returns the average distance of the graph + * @param considerWeights + * @param inverseWeights + * @param dropIsolates + * @return + */ +float Graph::distanceGraphAverage(const bool considerWeights, const bool inverseWeights, const bool dropIsolates){ if ( !distanceMatrixCreated || graphModified ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(false, considerWeights, inverseWeights,dropIsolates); + distanceMatrixCreate(false, considerWeights, inverseWeights,dropIsolates); } return averGraphDistance; } @@ -1513,7 +2153,7 @@ float Graph::averageGraphDistance(const bool considerWeights, int Graph::connectedness() { qDebug() << "Graph::connectedness() "; if (!reachabilityMatrixCreated || graphModified) { - reachabilityMatrix(false,false,false); + reachabilityMatrix(); } isolatedVertices=verticesIsolated().count(); if ( isSymmetric() ) { @@ -1564,7 +2204,7 @@ int Graph::connectedness() { /** * Writes the matrix of distances to a file */ -void Graph::writeDistanceMatrix (QString fn, const char* netName, +void Graph::writeDistanceMatrix (QString fn, QString netName, const bool considerWeights, const bool inverseWeights, const bool dropIsolates) { @@ -1572,7 +2212,7 @@ void Graph::writeDistanceMatrix (QString fn, const char* netName, if ( !distanceMatrixCreated || graphModified ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(false, considerWeights, inverseWeights, dropIsolates); + distanceMatrixCreate(false, considerWeights, inverseWeights, dropIsolates); } qDebug ("Graph::writeDistanceMatrix() writing to file"); @@ -1586,9 +2226,9 @@ void Graph::writeDistanceMatrix (QString fn, const char* netName, QTextStream outText(&file); outText.setCodec("UTF-8"); outText.setRealNumberPrecision(m_precision); - outText << "-Social Network Visualizer- \n"; - if (!netName) netName="Unnamed network"; - outText << "Distance matrix of "<< netName<<": \n"; + outText << "-Social Network Visualizer "<< VERSION <<"- \n"; + outText << "Network name: "<< ((netName.isEmpty()) ? "Unnamed" : netName) <<" \n"; + outText << "Distance matrix: \n"; outText << DM ; @@ -1601,13 +2241,13 @@ void Graph::writeDistanceMatrix (QString fn, const char* netName, * */ void Graph::writeNumberOfGeodesicsMatrix(const QString fn, - const char* netName, + const QString &netName, const bool considerWeights, const bool inverseWeights) { qDebug ("Graph::writeDistanceMatrix()"); if ( !distanceMatrixCreated || graphModified ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(false, considerWeights, inverseWeights, false); + distanceMatrixCreate(false, considerWeights, inverseWeights, false); } qDebug ("Graph::writeDistanceMatrix() writing to file"); @@ -1621,9 +2261,9 @@ void Graph::writeNumberOfGeodesicsMatrix(const QString fn, QTextStream outText(&file); outText.setCodec("UTF-8"); - outText << "-Social Network Visualizer- \n"; - if (!netName) netName="Unnamed network"; - outText << "Number of geodesics matrix of "<< netName<<": \n"; + outText << "-Social Network Visualizer "<< VERSION <<"- \n"; + outText << "Network name: "<< ((netName.isEmpty()) ? "Unnamed" : netName )<<" \n"; + outText << "Number of geodesics matrix: \n"; outText << TM ; @@ -1632,7 +2272,13 @@ void Graph::writeNumberOfGeodesicsMatrix(const QString fn, } - +/** + * @brief Graph::writeEccentricity + * @param fileName + * @param considerWeights + * @param inverseWeights + * @param dropIsolates + */ void Graph::writeEccentricity( const QString fileName, const bool considerWeights=false, const bool inverseWeights=false, const bool dropIsolates=false) @@ -1648,7 +2294,7 @@ void Graph::writeEccentricity( outText.setCodec("UTF-8"); if ( !distanceMatrixCreated || graphModified ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(true, considerWeights, + distanceMatrixCreate(true, considerWeights, inverseWeights, dropIsolates); } emit statusMessage ( QString(tr("Writing eccentricity to file:")).arg(fileName) ); @@ -1688,7 +2334,8 @@ void Graph::writeEccentricity( outText << "\n\n"; outText << tr("Eccentricity report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -1697,7 +2344,7 @@ void Graph::writeEccentricity( /** - * @brief Graph::createDistanceMatrix + * @brief Graph::distanceMatrixCreate Creates a matrix DM which stores geodesic distances between all vertices INPUT: boolean computeCentralities @@ -1716,24 +2363,24 @@ void Graph::writeEccentricity( - Power: * @param computeCentralities */ -void Graph::createDistanceMatrix(const bool centralities, +void Graph::distanceMatrixCreate(const bool centralities, const bool considerWeights, const bool inverseWeights, const bool dropIsolates) { - qDebug ("Graph::createDistanceMatrix()"); + qDebug ("Graph::distanceMatrixCreate()"); if ( !graphModified && distanceMatrixCreated && !centralities) { qDebug("Graph: distanceMatrix not mofified. Escaping."); return; } //Create a NxN DistanceMatrix. Initialise values to zero. m_totalVertices = vertices(false,true); - qDebug() << "Graph::createDistanceMatrix() Resizing Matrices to hold " + qDebug() << "Graph::distanceMatrixCreate() Resizing Matrices to hold " << m_totalVertices << " vertices"; DM.resize(m_totalVertices, m_totalVertices); TM.resize(m_totalVertices, m_totalVertices); XRM.zeroMatrix(m_totalVertices, m_totalVertices); - int aEdges = enabledEdges(); + int aEdges = edgesEnabled(); //drop isolated vertices from calculations (i.e. std C and group C). int aVertices=vertices(dropIsolates); @@ -1765,7 +2412,7 @@ void Graph::createDistanceMatrix(const bool centralities, << " outboundEdgesVert "<< outboundEdgesVert; qDebug() << " aEdges " << aEdges << " aVertices " << aVertices; - qDebug() << "Graph: createDistanceMatrix() - " + qDebug() << "Graph: distanceMatrixCreate() - " " initialising variables for maximum centrality indeces"; if (symmetricAdjacencyMatrix) { maxIndexBC=( aVertices-1.0) * (aVertices-2.0) / 2.0; @@ -1782,7 +2429,7 @@ void Graph::createDistanceMatrix(const bool centralities, qDebug("############# NOT SymmetricAdjacencyMatrix - maxIndexBC %f, maxIndexCC %f, maxIndexSC %f", maxIndexBC, maxIndexCC, maxIndexSC); } - qDebug("Graph: createDistanceMatrix() - initialising variables for centrality index"); + qDebug("Graph: distanceMatrixCreate() - initialising variables for centrality index"); maxCC=0; minCC=RAND_MAX; nomCC=0; denomCC=0; groupCC=0; maxNodeCC=0; minNodeCC=0; sumCC=0; discreteCCs.clear(); classesCC=0; @@ -1812,7 +2459,7 @@ void Graph::createDistanceMatrix(const bool centralities, //Zero closeness indeces of each vertex if (centralities) for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it) { - qDebug() << " Graph:createDistanceMatrix() - ZEROing all indices"; + qDebug() << " Graph:distanceMatrixCreate() - ZEROing all indices"; (*it)->setBC( 0.0 ); (*it)->setSC( 0.0 ); (*it)->setEccentricity( 0.0 ); @@ -2188,7 +2835,7 @@ void Graph::BFS(int s, const bool computeCentralities=false, it1=m_graph [ u ] ->m_outEdges.cbegin(); while ( it1!=m_graph [ u ] -> m_outEdges.cend() ){ relation = it1.value().first; - if ( relation != currentRelation() ) { + if ( relation != relationCurrent() ) { ++it1; continue; } @@ -2321,7 +2968,7 @@ void Graph::dijkstra(int s, const bool computeCentralities=false, for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it) { v=index[ (*it)->name() ]; if (v != s ){ - // DM initialization to RAND_MAX already done in createDistanceMatrix + // DM initialization to RAND_MAX already done in distanceMatrixCreate //DM.setItem(s,v,RAND_MAX); qDebug() << " push " << v << " to Q with infinite distance from s"; Q.push(Distance(v,RAND_MAX)); @@ -2354,7 +3001,7 @@ void Graph::dijkstra(int s, const bool computeCentralities=false, it1=m_graph [ u ] ->m_outEdges.cbegin(); while ( it1!=m_graph [ u ] -> m_outEdges.cend() ){ relation = it1.value().first; - if ( relation != currentRelation() ) { + if ( relation != relationCurrent() ) { ++it1; continue; } @@ -2494,7 +3141,7 @@ void Graph::dijkstra(int s, const bool computeCentralities=false, /** - minmax() facilitates the calculations of minimum and maximum centralities during createDistanceMatrix() + minmax() facilitates the calculations of minimum and maximum centralities during distanceMatrixCreate() */ void Graph::minmax(float C, Vertex *v, float &max, float &min, int &maxNode, int &minNode) { qDebug() << "MINMAX C = " << C << " max = " << max << " min = " << min << " name = " << v->name(); @@ -2513,7 +3160,7 @@ void Graph::minmax(float C, Vertex *v, float &max, float &min, int &maxNode, int /** This method calculates the number of discrete centrality classes of all vertices It stores that number in a QHash type where the centrality value is the key. - Called from createDistanceMatrix() + Called from distanceMatrixCreate() */ void Graph::resolveClasses(float C, H_StrToInt &discreteClasses, int &classes){ H_StrToInt::iterator it2; @@ -2542,12 +3189,14 @@ void Graph::resolveClasses(float C, H_StrToInt &discreteClasses, int &classes, i -/* Calculates the Information centrality of each vertex - diagonal included - * +/** + * @brief Graph::centralityInformation + * Calculates the Information centrality of each vertex - diagonal included * Note that there is no known generalization of Stephenson&Zelen's theory * for information centrality to directional data -*/ - + * @param considerWeights + * @param inverseWeights + */ void Graph::centralityInformation(const bool considerWeights, const bool inverseWeights){ qDebug()<< "Graph:: centralityInformation()"; @@ -2570,9 +3219,9 @@ void Graph::centralityInformation(const bool considerWeights, Otherwise, the TM might be singular, therefore non-invertible. */ bool dropIsolates=true; bool symmetrize=true; - createAdjacencyMatrix(dropIsolates, considerWeights, inverseWeights, symmetrize); + adjacencyMatrixCreate(dropIsolates, considerWeights, inverseWeights, symmetrize); - n-=isolatedVertices; //isolatedVertices updated in createAdjacencyMatrix + n-=isolatedVertices; //isolatedVertices updated in adjacencyMatrixCreate TM.resize(n, n); invM.resize(n, n); @@ -2708,7 +3357,8 @@ void Graph::writeCentralityInformation(const QString fileName, outText << tr("Information Centrality report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -2718,7 +3368,7 @@ void Graph::writeCentralityInformation(const QString fileName, -//Calculates the outDegree centrality of each vertex - diagonal included +//Calculates the degree (outDegree) centrality of each vertex - diagonal included void Graph::centralityDegree(const bool weights, const bool dropIsolates){ qDebug("Graph::centralityDegree()"); if (!graphModified && calculatedDC ) { @@ -2744,7 +3394,7 @@ void Graph::centralityDegree(const bool weights, const bool dropIsolates){ DC=0; if (!(*it)->isIsolated()) { for (it1=m_graph.cbegin(); it1!=m_graph.cend(); ++it1){ - if ( (weight=this->hasArc ( (*it)->name(), (*it1)->name() ) ) !=0 ) { + if ( (weight=edgeExists( (*it)->name(), (*it1)->name() ) ) !=0 ) { // qDebug() << "Graph::centralityDegree() - vertex " // << (*it)->name() // << " hasEdgeTo = " << (*it1)->name(); @@ -2754,8 +3404,7 @@ void Graph::centralityDegree(const bool weights, const bool dropIsolates){ DC++; //check here if the matrix is symmetric - we need this below - if ( ( this->hasArc ( (*it1)->name(), (*it)->name() ) ) != - ( this->hasArc ( (*it)->name(), (*it1)->name() ) ) ) + if ( edgeExists ( (*it1)->name(), (*it)->name() , true ) == 0 ) symmetricAdjacencyMatrix = false; } } @@ -2848,7 +3497,12 @@ void Graph::centralityDegree(const bool weights, const bool dropIsolates){ - +/** + * @brief Graph::writeCentralityDegree + * @param fileName + * @param considerWeights + * @param dropIsolates + */ void Graph::writeCentralityDegree ( const QString fileName, const bool considerWeights, const bool dropIsolates) @@ -2932,19 +3586,23 @@ void Graph::writeCentralityDegree ( const QString fileName, outText << "\n\n"; outText << tr("Degree Centrality (Out-Degree) Report, \n"); - outText << tr("created by SocNetV: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); } /** - * @brief Graph::centralityClosenessImproved + * @brief Graph::centralityClosenessInfluenceRange * Improved node-level centrality closeness index which focuses on the * influence range of each node (the set of nodes that are reachable from it) * For each node v, this index calculates the fraction of nodes in its influence * range and divides it by the average distance of those nodes from v, * ignoring nodes that are not reachable from it. + * @param considerWeights + * @param inverseWeights + * @param dropIsolates */ void Graph::centralityClosenessInfluenceRange(const bool considerWeights, const bool inverseWeights, @@ -2984,7 +3642,7 @@ void Graph::centralityClosenessInfluenceRange(const bool considerWeights, << " at distance " << DM.item ((*it)->name()-1, influencedVertices.at(i) ); IRCC += DM.item ((*it)->name()-1, influencedVertices.at(i) ) ; } - qDebug()<< "Graph:: centralityClosenessImproved - size of influenceRange Ji = " << Ji + qDebug()<< "Graph:: centralityClosenessImproved - size of vertexinfluenceRangee Ji = " << Ji << " IRCC=" << IRCC << " divided by Ji=" << Ji << " yields final IRCC =" << IRCC / Ji; // sanity check for IRCC=0 (=> node is disconnected) if (IRCC != 0) { @@ -3036,7 +3694,7 @@ void Graph::writeCentralityCloseness( if (graphModified || !calculatedCentralities ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(true, considerWeights, + distanceMatrixCreate(true, considerWeights, inverseWeights, dropIsolates); } else { @@ -3097,11 +3755,12 @@ void Graph::writeCentralityCloseness( outText <<"(Wasserman & Faust, formula 5.9, p. 186-187)\n\n"; } else - outText << tr("Because this graphs is weighted, we cannot compute Group Centralization\n") + outText << tr("Because this graph is weighted, we cannot compute Group Centralization\n") << tr("Use variance instead."); outText << "\n\n"; outText << tr("Closeness Centrality report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -3167,7 +3826,8 @@ void Graph::writeCentralityClosenessInfluenceRange(const QString fileName, outText << "\n\n"; outText << tr("InfluenceRange Closeness Centrality report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime(). + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime(). toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -3190,7 +3850,7 @@ void Graph::writeCentralityBetweenness(const QString fileName, if (graphModified || !calculatedCentralities ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(true, considerWeights, inverseWeights, dropIsolates); + distanceMatrixCreate(true, considerWeights, inverseWeights, dropIsolates); } else { qDebug() << " graph not modified, and centralities calculated. Returning"; @@ -3248,7 +3908,8 @@ void Graph::writeCentralityBetweenness(const QString fileName, outText << "\n\n"; outText << tr("Betweenness Centrality report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -3271,7 +3932,7 @@ void Graph::writeCentralityStress( const QString fileName, if (graphModified || !calculatedCentralities ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(true, considerWeights, inverseWeights,dropIsolates); + distanceMatrixCreate(true, considerWeights, inverseWeights,dropIsolates); } else { qDebug() << " graph not modified, and centralities calculated. Returning"; @@ -3328,14 +3989,21 @@ void Graph::writeCentralityStress( const QString fileName, outText << "\n\n"; outText << tr("Stress Centrality report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); } - +/** + * @brief Graph::writeCentralityEccentricity + * @param fileName + * @param considerWeights + * @param inverseWeights + * @param dropIsolates + */ void Graph::writeCentralityEccentricity(const QString fileName, const bool considerWeights, const bool inverseWeights, @@ -3350,7 +4018,7 @@ void Graph::writeCentralityEccentricity(const QString fileName, if (graphModified || !calculatedCentralities ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(true, considerWeights, inverseWeights,dropIsolates); + distanceMatrixCreate(true, considerWeights, inverseWeights,dropIsolates); } else { qDebug() << " graph not modified, and centralities calculated. Returning"; @@ -3388,7 +4056,8 @@ void Graph::writeCentralityEccentricity(const QString fileName, outText << "\n\n"; outText << tr("Eccentricity Centrality report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -3396,7 +4065,13 @@ void Graph::writeCentralityEccentricity(const QString fileName, - +/** + * @brief Graph::writeCentralityPower + * @param fileName + * @param considerWeights + * @param inverseWeights + * @param dropIsolates + */ void Graph::writeCentralityPower(const QString fileName, const bool considerWeights, const bool inverseWeights, @@ -3411,7 +4086,7 @@ void Graph::writeCentralityPower(const QString fileName, if (graphModified || !calculatedCentralities ) { emit statusMessage ( (tr("Calculating shortest paths")) ); - createDistanceMatrix(true, considerWeights, inverseWeights, dropIsolates); + distanceMatrixCreate(true, considerWeights, inverseWeights, dropIsolates); } else { qDebug() << " graph not modified, and centralities calculated. Returning"; @@ -3470,7 +4145,8 @@ void Graph::writeCentralityPower(const QString fileName, outText << "\n\n"; outText << tr("Power Centrality report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -3483,9 +4159,12 @@ void Graph::writeCentralityPower(const QString fileName, /** + * @brief Graph::prestigeDegree * Calculates Degree Prestige (in-degree) of each vertex - diagonal included * Also the mean value and the variance of the in-degrees. -*/ + * @param weights + * @param dropIsolates + */ void Graph::prestigeDegree(bool weights, bool dropIsolates=false){ qDebug()<< "Graph::prestigeDegree()"; if (!graphModified && calculatedDP ) { @@ -3511,15 +4190,14 @@ void Graph::prestigeDegree(bool weights, bool dropIsolates=false){ DP=0; if (!(*it)->isIsolated()) { for (it1=m_graph.cbegin(); it1!=m_graph.cend(); ++it1){ - if ( (weight=this->hasArc ( (*it1)->name(), (*it)->name() ) ) !=0 ) { + if ( (weight=edgeExists( (*it1)->name(), (*it)->name() ) ) !=0 ) { if (weights) DP+=weight; else DP++; } //check if the matrix is symmetric - we need this below - if ( ( this->hasArc ( (*it1)->name(), (*it)->name() ) ) - != ( this->hasArc ( (*it)->name(), (*it1)->name() ) ) ) + if ( edgeExists ( (*it1)->name(), (*it)->name() , true) == 0 ) symmetricAdjacencyMatrix = false; } } @@ -3595,7 +4273,12 @@ void Graph::prestigeDegree(bool weights, bool dropIsolates=false){ - +/** + * @brief Graph::writePrestigeDegree + * @param fileName + * @param considerWeights + * @param dropIsolates + */ void Graph::writePrestigeDegree (const QString fileName, const bool considerWeights, const bool dropIsolates) @@ -3616,7 +4299,7 @@ void Graph::writePrestigeDegree (const QString fileName, outText << tr("The DP index of a node u is the sum of inbound edges to " "that node from all adjacent nodes.\n"); outText << tr("If the network is weighted, DP is the sum of inbound arc " - "weights (inDegree) to node u from all adjacent nodes.\n"); + "weights (Indegree) to node u from all adjacent nodes.\n"); outText << tr("The DP index is also known as InDegree Centrality.") << "\n"; outText << tr("DP' is the standardized DP (divided by N-1)\n\n"); if (considerWeights){ @@ -3670,7 +4353,8 @@ void Graph::writePrestigeDegree (const QString fileName, outText << "\n\n"; outText << tr("Degree Prestige Report, \n"); - outText << tr("created by SocNetV: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -3696,7 +4380,7 @@ void Graph::prestigeProximity( const bool considerWeights, if (!reachabilityMatrixCreated || graphModified) { qDebug()<< "Graph::prestigeProximity() - " "call reachabilityMatrix()"; - reachabilityMatrix(considerWeights, inverseWeights, dropIsolates); + reachabilityMatrix(considerWeights, inverseWeights, dropIsolates, false); } // calculate centralities QList::const_iterator it; @@ -3727,7 +4411,7 @@ void Graph::prestigeProximity( const bool considerWeights, PP += DM.item ( influencerVertices.at(i), (*it)->name()-1); } qDebug()<< "Graph::PP - " - "size of influenceDomain Ii = " << Ii + "size of vertexinfluenceDomain Ii = " << Ii << " PP=" << PP << " divided by Ii=" << Ii << " yields graph-dependant PP index =" << PP / Ii; @@ -3787,7 +4471,15 @@ void Graph::prestigeProximity( const bool considerWeights, -//Writes the proximity prestige indeces to a file + +/** + * @brief Graph::writePrestigeProximity + * Writes the proximity prestige indices to a file + * @param fileName + * @param considerWeights + * @param inverseWeights + * @param dropIsolates + */ void Graph::writePrestigeProximity( const QString fileName, const bool considerWeights, const bool inverseWeights, @@ -3840,7 +4532,8 @@ void Graph::writePrestigeProximity( const QString fileName, outText << "\n\n"; outText << tr("Proximity Prestige report, \n"); - outText << tr("created by SocNetV on: ")<< actualDateTime.currentDateTime() + outText << tr("Created by SocNetV ") << VERSION << ": " + << actualDateTime.currentDateTime() .toString ( QString ("ddd, dd.MMM.yyyy hh:mm:ss")) << "\n\n"; file.close(); @@ -3849,7 +4542,12 @@ void Graph::writePrestigeProximity( const QString fileName, -//Calculates the PageRank Prestige of each vertex + +/** + * @brief Graph::prestigePageRank + * Calculates the PageRank Prestige of each vertex + * @param dropIsolates + */ void Graph::prestigePageRank(const bool dropIsolates){ qDebug()<< "Graph::prestigePageRank()"; if (! graphModified && calculatedPRP ) { @@ -3902,7 +4600,7 @@ void Graph::prestigePageRank(const bool dropIsolates){ << " outLinks (set const): " << outLinks; } - if ( enabledEdges() == 0 ) { + if ( edgesEnabled() == 0 ) { qDebug()<< "Graph::prestigePageRank() " <<" - all vertices are isolated and of equal PR. Stop"; return; @@ -3938,7 +4636,7 @@ void Graph::prestigePageRank(const bool dropIsolates){ while ( jt != (*it) -> m_inEdges.cend() ) { relation = jt.value().first; - if ( relation != currentRelation() ){ + if ( relation != relationCurrent() ){ ++jt; continue; } @@ -3954,7 +4652,7 @@ void Graph::prestigePageRank(const bool dropIsolates){ << " inLinked from neighbor " << referrer << " index " << index[referrer]; - if ( this->hasArc( referrer , (*it)->name() ) ) + if ( edgeExists( referrer , (*it)->name() ) ) { inLinks = m_graph[ index[referrer] ] ->inEdgesConst(); outLinks = m_graph[ index[referrer] ]-> outEdgesConst(); @@ -4059,184 +4757,71 @@ void Graph::prestigePageRank(const bool dropIsolates){ variancePRP = variancePRP / (aVert); qDebug() << "PRP' Variance: " << variancePRP ; - calculatedPRP= true; - - return; - -} - - -//Writes the PageRank indices to a file -void Graph::writePrestigePageRank(const QString fileName, const bool dropIsolates){ - QFile file ( fileName ); - if ( !file.open( QIODevice::WriteOnly ) ) { - qDebug()<< "Error opening file!"; - emit statusMessage (QString(tr("Could not write to %1")).arg(fileName) ); - return; - } - QTextStream outText ( &file ); outText.setCodec("UTF-8"); - - emit statusMessage ( (tr("Calculating PageRank indices. Please wait...")) ); - - prestigePageRank(dropIsolates); - - emit statusMessage ( QString(tr("Writing PageRank indices to file: %1")) - .arg(fileName) ); - outText.setRealNumberPrecision(m_precision); - outText << tr("PAGERANK PRESTIGE (PRP)")<<"\n"; - outText << tr("")<<"\n"; - outText << tr("PRP range: (1-d)/N = ") << ( 1- d_factor ) / vertices() - << " < PRP" << endl; - outText << " d =" << d_factor << endl; - outText << tr("PRP' is the standardized PR (PR divided by sumPR)")<<"\n"; - outText << tr("PRP' range: ") << " (1-d)/N < C'< 1" <<"\n\n"; - outText << "Node"<<"\tPRP\t\tPRP'\t\t%PRP'\n"; - QList::const_iterator it; - float PRP=0, SPRP=0; - for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ - PRP = (*it)->PRP(); - SPRP = (*it)->SPRP(); - outText << (*it)->name()<<"\t"<< PRP << "\t\t"<< SPRP << "\t\t" - << ( 100* SPRP )<::const_iterator it; - for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ - outText << (*it)->name()<<"\t"<<(*it)->CLC() <::const_iterator it; + float PRP=0, SPRP=0; + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + PRP = (*it)->PRP(); + SPRP = (*it)->SPRP(); + outText << (*it)->name()<<"\t"<< PRP << "\t\t"<< SPRP << "\t\t" + << ( 100* SPRP )< (maxWidth) ); - new_y= rand() % ( static_cast (maxHeight) ); + Vertices::const_iterator it; + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + new_x= 10 + rand() % ( canvasWidth ); + new_y= 10 + rand() % ( canvasHeight ); (*it)->setX( new_x ); (*it)->setY( new_y ); - qDebug()<< "Graph: Emitting moveNode to move Vertice " << (*it)->name() - //<< "indexed " << index((*it)->name()) - << " to new position " << new_x << " , "<< new_y; + qDebug()<< "Graph::layoutRandom() - " + << " vertex " << (*it)->name() + << " emitting moveNode to new pos " << new_x << " , "<< new_y; emit moveNode((*it)->name(), new_x, new_y); } graphModified=true; @@ -4455,6 +5054,7 @@ void Graph::layoutCircularRandom(double x0, double y0, double maxRadius){ qDebug() << "Graph::layoutCircularRandom - "; double rad=0, new_radius=0, new_x=0, new_y=0; double i=0; + maxRadius = canvasMinDimension(); //offset controls how far from the centre the central nodes be positioned float offset=0.06, randomDecimal=0; int vert=vertices(); @@ -4479,11 +5079,7 @@ void Graph::layoutCircularRandom(double x0, double y0, double maxRadius){ //Move node to new position emit moveNode((*it)->name(), new_x, new_y); i++; - emit addGuideCircle ( - static_cast (x0), - static_cast (y0), - static_cast (new_radius) - ); + emit addGuideCircle ( x0, y0, new_radius ); } graphModified=true; } @@ -4491,10 +5087,17 @@ void Graph::layoutCircularRandom(double x0, double y0, double maxRadius){ -/** -* Repositions all nodes on different top-down levels according to their centrality -* Emits moveNode(i, x,y) to tell GW that the node item should be moved. -*/ +/** + * @brief Graph::layoutLevelByProminenceIndex + * Repositions all nodes on different top-down levels according to their centrality + * Emits moveNode(i, x,y) to tell GW that the node item should be moved. + * @param maxWidth + * @param maxHeight + * @param prominenceIndex + * @param considerWeights + * @param inverseWeights + * @param dropIsolates + */ void Graph::layoutLevelByProminenceIndex(double maxWidth, double maxHeight, int prominenceIndex, const bool considerWeights, @@ -4528,7 +5131,7 @@ void Graph::layoutLevelByProminenceIndex(double maxWidth, double maxHeight, } else{ if (graphModified || !calculatedCentralities ) - createDistanceMatrix(true, considerWeights, + distanceMatrixCreate(true, considerWeights, inverseWeights, dropIsolates); } @@ -4648,7 +5251,7 @@ void Graph::layoutLevelByProminenceIndex(double maxWidth, double maxHeight, //Move node to new position emit moveNode((*it)->name(), new_x, new_y); i++; - emit addGuideHLine(static_cast ( new_y ) ); + emit addGuideHLine(new_y); } // graphModified=true; // emit graphChanged(); @@ -4702,7 +5305,7 @@ void Graph::layoutVerticesSizeByProminenceIndex (int prominenceIndex, } else{ if (graphModified || !calculatedCentralities ) - createDistanceMatrix(true, considerWeights, + distanceMatrixCreate(true, considerWeights, inverseWeights, dropIsolates); } QList::const_iterator it; @@ -4823,10 +5426,12 @@ void Graph::layoutVerticesSizeByProminenceIndex (int prominenceIndex, + /** - Adds a little universal randomness :) -*/ -void Graph::makeThingsLookRandom() { + * @brief Graph::randomizeThings + * Adds a little universal randomness :) + */ +void Graph::randomizeThings() { time_t now; /* define 'now'. time_t is probably a typedef */ now = time((time_t *)NULL); /* Get the system time and put it * into 'now' as 'calender time' the number of seconds since 1/1/1970 */ @@ -4836,56 +5441,67 @@ void Graph::makeThingsLookRandom() { -/** layman's attempt to create a random network -*/ -void Graph::createRandomNetErdos( const int &vert, +/** + * @brief Graph::randomNetErdosCreate + * @param vert + * @param model + * @param edges + * @param eprob + * @param mode + * @param diag + * Create an erdos-renyi random network according to the given model + */ +void Graph::randomNetErdosCreate( const int &vert, const QString &model, const int &edges, const float &eprob, const QString &mode, const bool &diag) { - qDebug() << "Graph::createRandomNetErdos() - vertices " << vert + qDebug() << "Graph::randomNetErdosCreate() - vertices " << vert << " model " << model << " edges " << edges << " edge probability " << eprob << " graph mode " << mode - << " diag " << diag; + << " diag " << diag + << " canvasWidth " < " << j+1; if (!diag && i==j) { - qDebug()<< " Graph::createRandomNetErdos() - skip because " + qDebug()<< " Graph::randomNetErdosCreate() - skip because " << i+1 << " = " << j+1 << " and diag " << diag; continue; @@ -4894,64 +5510,71 @@ void Graph::createRandomNetErdos( const int &vert, edgeCount ++ ; if (mode == "graph") { - qDebug() << "Graph::createRandomNetErdos() - " + qDebug() << "Graph::randomNetErdosCreate() - " <<" create undirected Edge no " << edgeCount; - createEdge(i+1, j+1, 1, "black", 2, true, false); + edgeCreate(i+1, j+1, 1, initEdgeColor, + EDGE_RECIPROCAL_UNDIRECTED, false, false, + QString::null, false); } else { - qDebug() << "Graph::createRandomNetErdos() - " + qDebug() << "Graph::randomNetErdosCreate() - " <<" create directed Edge no " << edgeCount; - createEdge(i+1, j+1, 1, "black", 0, true, false); + edgeCreate(i+1, j+1, 1, initEdgeColor, + EDGE_DIRECTED, true, false, + QString::null, false); } } else - qDebug() << "Graph::createRandomNetErdos() - do not create Edge"; + qDebug() << "Graph::randomNetErdosCreate() - do not create Edge"; } - progressCounter++; - emit updateProgressDialog(progressCounter ); - qDebug("Emitting UPDATE PROGRESS %i", progressCounter); + + emit updateProgressDialog(++progressCounter ); + } } else { - qDebug() << "Graph::createRandomNetErdos() - G(n,M) model..."; + qDebug() << "Graph::randomNetErdosCreate() - G(n,M) model..."; int source = 0, target = 0 ; do { source = rand() % vert + 1; target = rand() % vert + 1; - qDebug() << "Graph::createRandomNetErdos() - random pair " + qDebug() << "Graph::randomNetErdosCreate() - random pair " << " " << source << " , " << target ; if (!diag && source == target ) { - qDebug() << "Graph::createRandomNetErdos() - skip self loop pair "; + qDebug() << "Graph::randomNetErdosCreate() - skip self loop pair "; continue; } - if ( hasArc(source, target) ) { - qDebug() << "Graph::createRandomNetErdos() - skip pair - exists"; + if ( edgeExists(source, target) ) { + qDebug() << "Graph::randomNetErdosCreate() - skip pair - exists"; continue; } edgeCount ++; if (mode == "graph") { - qDebug() << "Graph::createRandomNetErdos() - create " + qDebug() << "Graph::randomNetErdosCreate() - create " << " undirected Edge no " << edgeCount; - createEdge(source, target, 1, "black", 2, true, false); + edgeCreate(source, target, 1, initEdgeColor, + EDGE_RECIPROCAL_UNDIRECTED, false, false, + QString::null, false); } else { - qDebug() << "Graph::createRandomNetErdos() - create " + qDebug() << "Graph::randomNetErdosCreate() - create " << " directed Edge no " << edgeCount; - createEdge(source, target, 1, "black", 0, true, false); + edgeCreate(source, target, 1, initEdgeColor, + EDGE_DIRECTED, true, false, + QString::null, false); } - + emit updateProgressDialog(++progressCounter ); } while ( edgeCount != edges ); } - - addRelationFromGraph(tr("erdos-renyi")); //FIXME + relationAddFromGraph(tr("1")); emit graphChanged(); } @@ -4959,12 +5582,21 @@ void Graph::createRandomNetErdos( const int &vert, -/** layman's attempt to create a random ring lattice network. -*/ -void Graph::createRandomNetRingLattice( - int vert, int degree, - double x0, double y0, double radius) +/** + * @brief Graph::randomNetRingLatticeCreate + * Creates a random ring lattice network. + * @param vert + * @param degree + * @param x0 + * @param y0 + * @param radius + * @param updateProgress + */ +void Graph::randomNetRingLatticeCreate( const int &vert, const int °ree, + const double &x0, const double &y0, + const double &radius, + const bool updateProgress) { qDebug("Graph: createRingLatticeNetwork"); int x=0; @@ -4973,43 +5605,45 @@ void Graph::createRandomNetRingLattice( double rad= (2.0* Pi/ vert ); - makeThingsLookRandom(); +// if (mode=="graph") { + undirectedSet(true); +// } + + randomizeThings(); index.reserve(vert); - for (register int i=0; i< vert ; i++) { + for (int i=0; i< vert ; i++) { x=x0 + radius * cos(i * rad); y=y0 + radius * sin(i * rad); - createVertex( i+1,initVertexSize,initVertexColor, + vertexCreate( i+1,initVertexSize,initVertexColor, initVertexNumberColor, initVertexNumberSize, QString::number (i+1), initVertexLabelColor, initVertexLabelSize, QPoint(x, y), initVertexShape, false); qDebug("Graph: createPhysicistLatticeNetwork, new node i=%i, at x=%i, y=%i", i+1, x,y); - progressCounter++; - emit updateProgressDialog( progressCounter ); } int target = 0; - for (register int i=0;i " << j+1; - createEdge (i+1, j+1, 1, "black", 2, true, false); + edgeCreate (i+1, j+1, 1, initEdgeColor, + EDGE_RECIPROCAL_UNDIRECTED, false, false, + QString::null, false); } - progressCounter++; - emit updateProgressDialog(progressCounter ); + emit updateProgressDialog( ++progressCounter ); } - qDebug()<< endl << "Graph::createRandomNetScaleFree() - " + qDebug()<< endl << "Graph::randomNetScaleFreeCreate() - " << " start network growth to " << n << " nodes with preferential attachment" << endl; - for (register int i= m0 ; i < n ; ++i) { + for (int i= m0 ; i < n ; ++i) { x=x0 + radius * cos(i * rad); y=y0 + radius * sin(i * rad); - qDebug() << "Graph::createRandomNetScaleFree() - " + qDebug() << "Graph::randomNetScaleFreeCreate() - " << " adding new node i " << i+1 << " pos " << x << "," << y << endl; - createVertex( + vertexCreate( i+1, initVertexSize,initVertexColor, initVertexNumberColor, initVertexNumberSize, QString::number (i+1), initVertexLabelColor, initVertexLabelSize, QPoint(x, y), initVertexShape,false ); - progressCounter++; - emit updateProgressDialog( progressCounter ); - // no need to multiply by 2, since enabledEdges already reports - // twice the current number of edges in the network - sumDegrees = enabledEdges(); + emit updateProgressDialog( ++progressCounter ); + + // need to multiply by 2, since we have a undirected graph + // and edgesEnabled reports edges/2 + sumDegrees = 2 * edgesEnabled(); newEdges = 0; for (;;) { //do until we create m new edges - for (register int j=0; j < i ; ++j) { - qDebug() << "Graph::createRandomNetScaleFree() - " + for (int j=0; j < i ; ++j) { + qDebug() << "Graph::randomNetScaleFreeCreate() - " << " preferential attachment test of new node i " << i+1 << " with node j " << j+1 @@ -5104,7 +5741,7 @@ void Graph::createRandomNetScaleFree (const int &n, if (newEdges == m) break; - k_j = inDegree(j+1); + k_j = vertexDegreeIn(j+1); k_j = pow ( k_j , power ); if (sumDegrees < 1 ) prob_j = 1; // always create edge if no other edge exist @@ -5113,7 +5750,7 @@ void Graph::createRandomNetScaleFree (const int &n, prob = ( rand() % 100 + 1 ) / 100.0; - qDebug() << "Graph::createRandomNetScaleFree() - " + qDebug() << "Graph::randomNetScaleFreeCreate() - " << " Edge probability with old node " << j+1 << " is: alpha + k_j ^ power " << alpha + k_j << " / sumDegrees " << sumDegrees @@ -5124,14 +5761,18 @@ void Graph::createRandomNetScaleFree (const int &n, if ( mode == "graph") { qDebug() << " --- Creating pref.att. reciprocal edge " << i+1 << " <-> " << j+1; - createEdge (i+1, j+1, 1, "black", 2, true, false); + edgeCreate (i+1, j+1, 1, initEdgeColor, + EDGE_RECIPROCAL_UNDIRECTED, false, false, + QString::null, false); newEdges ++; } else { qDebug() << " --- Creating pref.att. directed edge " << i+1 << " <-> " << j+1; - createEdge (i+1, j+1, 1, "black", 1, true, false); + edgeCreate (i+1, j+1, 1, initEdgeColor, + EDGE_DIRECTED_OPPOSITE_EXISTS, true, false, + QString::null, false); newEdges ++; } @@ -5142,48 +5783,69 @@ void Graph::createRandomNetScaleFree (const int &n, } } - addRelationFromGraph(tr("scale-free")); - emit signalNodeSizesByInDegree(true); + relationAddFromGraph(tr("1")); emit graphChanged(); + emit signalNodeSizesByInDegree(true); //FIXME } -void Graph::createRandomNetSmallWorld ( - int vert, int degree, double beta, - double x0, double y0, double radius) +/** + * @brief Graph::randomNetSmallWorldCreate + * Creates a small world network + * @param vert + * @param degree + * @param beta + * @param x0 + * @param y0 + * @param radius + */ +void Graph::randomNetSmallWorldCreate (const int &vert, const int °ree, + const double &beta, const QString &mode, + const double &x0, const double &y0, + const double &radius) { - qDebug("Graph: createRandomNetSmallWorld. First creating a ring lattice"); + qDebug() << "Graph:randomNetSmallWorldCreate() -. " + << "vertices: " << vert + << "degree: " << degree + << "beta: " << beta + << "mode: " << mode + << "First creating a ring lattice"; + + if (mode=="graph") { + undirectedSet(true); + } - createRandomNetRingLattice(vert, degree, x0, y0, radius); + randomNetRingLatticeCreate(vert, degree, x0, y0, radius, false); qDebug("******** Graph: REWIRING starts..."); int candidate; - - for (register int i=1;i>>>> REWIRING: Check if "<< i << " is linked to " << j; - if ( this-> hasArc(i, j) ) { + if ( edgeExists(i, j) ) { qDebug()<<">>>>> REWIRING: They're linked. Do a random REWIRING " "Experiment between "<< i<< " and " << j << " Beta parameter is " << beta; if (rand() % 100 < (beta * 100)) { qDebug(">>>>> REWIRING: We'l break this edge!"); - removeEdge(i, j); - removeEdge(j, i); + edgeRemove(i, j, true); qDebug()<<">>>>> REWIRING: OK. Let's create a new edge!"; for (;;) { //do until we create a new edge candidate=rand() % (vert+1) ; //pick another vertex. if (candidate == 0 || candidate == i) continue; qDebug()<<">>>>> REWIRING: Candidate: "<< candidate; //Only if differs from i and hasnot edge with it - if (! this->hasArc(i, candidate) ) + if ( edgeExists(i, candidate) == 0) qDebug("<----> Random New Edge Experiment between %i and %i:", i, candidate); if (rand() % 100 > 0.5) { qDebug("Creating new link!"); - createEdge(i, candidate, 1, "black", true, true, false); + edgeCreate(i, candidate, 1, initEdgeColor, + EDGE_RECIPROCAL_UNDIRECTED, false, false, + QString::null, false); break; } } @@ -5191,71 +5853,87 @@ void Graph::createRandomNetSmallWorld ( else qDebug("Will not break link!"); } } + emit updateProgressDialog( ++progressCounter ); } emit signalNodeSizesByInDegree(true); + emit graphChanged(); } -/** layman's attempt to create a random network where nodes have the same degree. -*/ -void Graph::createSameDegreeRandomNetwork(int vert, int degree){ - qDebug("Graph: createSameDegreeRandomNetwork"); +/** + * @brief Graph::randomNetSameDegreeCreate + * Creates a random network where nodes have the same degree. + * @param vert + * @param degree + */ +void Graph::randomNetSameDegreeCreate( const int &vert, + const int °ree + ){ + qDebug("Graph: randomNetSameDegreeCreate"); int progressCounter=0; - makeThingsLookRandom(); + randomizeThings(); index.reserve(vert); - for (register int i=0; i< vert ; i++) { - int x=10+rand() %640; - int y=10+rand() %480; + int x = 0, y = 0 ; + + for (int i=0; i< vert ; i++) { + x=10+rand() % canvasWidth; + y=10+rand() % canvasHeight; qDebug("Graph: createUniformRandomNetwork, new node i=%i, at x=%i, y=%i", i+1, x,y); - createVertex( + vertexCreate( i+1, initVertexSize,initVertexColor, initVertexNumberColor, initVertexNumberSize, QString::number (i+1), initVertexLabelColor, initVertexLabelSize, QPoint(x, y), initVertexShape,false ); - progressCounter++; - emit updateProgressDialog( progressCounter ); - } int target = 0; - for (register int i=0;i Graph::influenceRange(int v1){ - qDebug() << "Graph::influenceRange() "; +QList Graph::vertexinfluenceRange(int v1){ + qDebug() << "Graph::vertexinfluenceRange() "; if (!reachabilityMatrixCreated || graphModified) { // call reachabilityMatrix to construct a list of influence ranges // for each node @@ -5386,13 +6077,17 @@ QList Graph::influenceRange(int v1){ + /** + * @brief Graph::vertexinfluenceDomain * Returns the influence domain of vertex v1, namely the set of nodes who can * reach v1 - * This function is for digraphs only + * This function applies to digraphs only + * @param v1 + * @return */ -QList Graph::influenceDomain(int v1){ - qDebug() << "Graph::influenceDomain() "; +QList Graph::vertexinfluenceDomain(int v1){ + qDebug() << "Graph::vertexinfluenceDomain() "; if (!reachabilityMatrixCreated || graphModified) { // call reachabilityMatrix to construct a list of influence domains // for each node @@ -5412,9 +6107,10 @@ QList Graph::influenceDomain(int v1){ In the process, this function creates the InfluenceRange and InfluenceDomain of each node. */ -void Graph::reachabilityMatrix( const bool considerWeights, - const bool inverseWeights, - const bool dropIsolates) { +void Graph::reachabilityMatrix(const bool considerWeights, + const bool inverseWeights, + const bool dropIsolates, + const bool updateProgress) { qDebug()<< "Graph::reachabilityMatrix()"; if (reachabilityMatrixCreated && !graphModified) { @@ -5424,7 +6120,7 @@ void Graph::reachabilityMatrix( const bool considerWeights, } else { - createDistanceMatrix(false, considerWeights,inverseWeights,dropIsolates); + distanceMatrixCreate(false, considerWeights,inverseWeights,dropIsolates); int size = vertices(false,false), i=0, j=0; qDebug()<< "Graph::reachabilityMatrix() - calculating XRM..." ; influenceRanges.clear(); @@ -5447,8 +6143,8 @@ void Graph::reachabilityMatrix( const bool considerWeights, qDebug()<< "Graph::reachabilityMatrix() - inverse path d(" <::const_iterator it; + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ + outText << (*it)->name()<<"\t"<<(*it)->CLC() <name()); + cliquesContaining ((*it)->name()); outText << (*it)->name()<<"\t"<< (*it)->cliques(2) << "\t" << (*it)->cliques(3) << "\t"<< (*it)->cliques(4) < &list){ - qDebug() << "*** Graph::addClique()" << + +/** + * @brief Graph::cliqueAdd + * @param list + * @return + */ +bool Graph:: cliqueAdd(const QList &list){ + qDebug() << "*** Graph::cliqueAdd()" << list.count(); for (int i = 0; i < list.size(); ++i) { - qDebug() << "*** Graph::addClique() - Found vertex " << list.at(i) + qDebug() << "*** Graph::cliqueAdd() - Found vertex " << list.at(i) << " at position " << i << endl; } @@ -5624,13 +6457,13 @@ bool Graph:: addClique(const QList &list){ ! cliques_2_Vertex.contains(dyad_alt) ) { cliques_2_Vertex.insert(dyad, true); - qDebug() << "*** Graph::addClique() - new 2-vertex clique " + qDebug() << "*** Graph::cliqueAdd() - new 2-vertex clique " << " adding it to global list "; } - if ( m_graph[ index[list.at(0)] ]->addClique(dyad,list.size()) ) { - qDebug() << "*** Graph::addClique() - new 2-vertex clique: " + if ( m_graph[ index[list.at(0)] ]->cliqueAdd(dyad,list.size()) ) { + qDebug() << "*** Graph::cliqueAdd() - new 2-vertex clique: " << list.at(0) << "," << list.at(1) ; return true; } @@ -5659,11 +6492,11 @@ bool Graph:: addClique(const QList &list){ ! cliques_3_Vertex.contains(triad_alt5) ) { cliques_3_Vertex.insert(triad, true); - qDebug() << "*** Graph::addClique() - new 3-vertex clique " + qDebug() << "*** Graph::cliqueAdd() - new 3-vertex clique " << " adding it to global list "; } - if ( m_graph[ index[list.at(0)] ]->addClique(triad,list.size()) ) { - qDebug() << "*** Graph::addClique() - new 3-vertex clique: " + if ( m_graph[ index[list.at(0)] ]->cliqueAdd(triad,list.size()) ) { + qDebug() << "*** Graph::cliqueAdd() - new 3-vertex clique: " << list.at(0) << "," << list.at(1) << "," << list.at(2) ; return true; } @@ -5722,13 +6555,13 @@ bool Graph:: addClique(const QList &list){ + ", " + QString::number(list.at( (3) ) ); if (! knownClique) { cliques_4_Vertex.insert(quart, true); - qDebug() << "*** Graph::addClique() - new 4-vertex clique " + qDebug() << "*** Graph::cliqueAdd() - new 4-vertex clique " << quart << " adding it to global list "; } - if ( m_graph[ index[list.at(0)] ]->addClique(quart,list.size()) ) { - qDebug() << "*** Graph::addClique() - new 4-vertex clique: " + if ( m_graph[ index[list.at(0)] ]->cliqueAdd(quart,list.size()) ) { + qDebug() << "*** Graph::cliqueAdd() - new 4-vertex clique: " << list.at(0) << "," << list.at(1) << "," << list.at(2) << "," << list.at(3) ; return true; @@ -5746,8 +6579,8 @@ bool Graph:: addClique(const QList &list){ Due to computational complexity, SocNetV computes 2-vertex, 3-vertex and 4-vertex cliques only. */ -float Graph:: countCliquesWith(int source, int size){ - qDebug() << "*** Graph::countCliquesWith(" << source << ")"; +float Graph:: cliquesContaining(int source, int size){ + qDebug() << "*** Graph::cliquesContaining(" << source << ")"; int vert1=0, vert2=0, vert3=0; int relation=0; @@ -5757,18 +6590,18 @@ float Graph:: countCliquesWith(int source, int size){ QList dyad, triad, quad; - qDebug() << "Graph::countCliquesWith() Source vertex " << source - << "[" << index[source] << "] has inEdges " << inboundEdges(source) - << " and outEdges "<< outboundEdges(source); + qDebug() << "Graph::cliquesContaining() Source vertex " << source + << "[" << index[source] << "] has inEdges " << edgesInbound(source) + << " and outEdges "<< edgesOutbound(source); - qDebug () << "Graph::countCliquesWith() - Checking inEdges to " << source; + qDebug () << "Graph::cliquesContaining() - Checking inEdges to " << source; it1=m_graph [ index[source] ] ->m_inEdges.cbegin(); while ( it1!=m_graph [ index[source] ] -> m_inEdges.cend() ){ relation = it1.value().first; - if ( relation != currentRelation() ) { + if ( relation != relationCurrent() ) { ++it1; continue; } @@ -5779,40 +6612,40 @@ float Graph:: countCliquesWith(int source, int size){ } vert1 = it1.key(); // weight = it1.value().second.first; - qDebug() << "Graph::countCliquesWith() - inLink from 1st neighbor " + qDebug() << "Graph::cliquesContaining() - inLink from 1st neighbor " << vert1 << "[" << index[vert1] << "] "; if (source == vert1) { - qDebug() << "Graph::countCliquesWith() - It's the source - CONTINUE"; + qDebug() << "Graph::cliquesContaining() - It's the source - CONTINUE"; ++it1; continue; } - if ( this->hasArc( source, vert1 ) == 0 ) { - qDebug() << "Graph::countCliquesWith() - incomplete 2v-subgraph - CONTINUE"; + if ( edgeExists( source, vert1 ) == 0 ) { + qDebug() << "Graph::cliquesContaining() - incomplete 2v-subgraph - CONTINUE"; ++it1; continue; } - qDebug() << "Graph::countCliquesWith() - complete 2v-subgraph "; + qDebug() << "Graph::cliquesContaining() - complete 2v-subgraph "; dyad.clear(); dyad << source << vert1; - if ( addClique( dyad ) ) { - qDebug() << "Graph::countCliquesWith() - 2v cliques " + if ( cliqueAdd( dyad ) ) { + qDebug() << "Graph::cliquesContaining() - 2v cliques " << cliques_2_Vertex.count(); } - qDebug() << "Graph::countCliquesWith() - " + qDebug() << "Graph::cliquesContaining() - " << " Iterate over all inEdges of " << vert1; it2=m_graph [ index[vert1] ] ->m_inEdges.cbegin(); while ( it2!=m_graph [ index[vert1] ] -> m_inEdges.cend() ){ relation = it2.value().first; - if ( relation != currentRelation() ){ + if ( relation != relationCurrent() ){ ++it2; continue; } @@ -5822,51 +6655,51 @@ float Graph:: countCliquesWith(int source, int size){ continue; } vert2 = it2.key(); - qDebug() << "Graph::countCliquesWith() - Possible other neighbor (for 3v clique)" + qDebug() << "Graph::cliquesContaining() - Possible other neighbor (for 3v clique)" << vert2 << "[" << index[vert2] << "]"; if (source == vert2) { - qDebug() << "Graph::countCliquesWith() - It's the source - CONTINUE"; + qDebug() << "Graph::cliquesContaining() - It's the source - CONTINUE"; ++it2; continue; } if (vert1 == vert2) { - qDebug() << "Graph::countCliquesWith() - It's the vert1 - CONTINUE"; + qDebug() << "Graph::cliquesContaining() - It's the vert1 - CONTINUE"; ++it2; continue; } - if ( this->hasArc( vert1, vert2 ) == 0 ) { - qDebug() << "Graph::countCliquesWith() - " + if ( edgeExists( vert1, vert2 ) == 0 ) { + qDebug() << "Graph::cliquesContaining() - " << vert1 << " not outLinked to " << vert2 << " - incomplete 3vertex-subgraph - CONTINUE"; ++it2; continue; } else { - qDebug() << "Graph::countCliquesWith() - complete 3vertex-subgraph ? " + qDebug() << "Graph::cliquesContaining() - complete 3vertex-subgraph ? " << vert2 << " <-> " << vert1 << ". Checking if " << vert2 << " <-> " << source << " ... "; - if ( this->hasEdge( source, vert2 ) ) { + if ( edgeExists( source, vert2, true ) ) { - qDebug() << "Graph::countCliquesWith() - complete 3v-subgraph " + qDebug() << "Graph::cliquesContaining() - complete 3v-subgraph " << source << " <-> " << vert2 << " possible (new?) 3-vertex clique: "; triad.clear(); triad << source << vert1 << vert2; - if ( addClique( triad ) ) { - qDebug() << "Graph::countCliquesWith() - 3-vertex cliques " + if ( cliqueAdd( triad ) ) { + qDebug() << "Graph::cliquesContaining() - 3-vertex cliques " << cliques_3_Vertex.count(); } - qDebug() << "Graph::countCliquesWith() - " + qDebug() << "Graph::cliquesContaining() - " << " Iterate over all inEdges of " << vert2; it3=m_graph [ index[vert2] ] ->m_inEdges.cbegin(); while ( it3!=m_graph [ index[vert2] ] -> m_inEdges.cend() ){ relation = it3.value().first; - if ( relation != currentRelation() ){ + if ( relation != relationCurrent() ){ ++it3; continue; } @@ -5876,27 +6709,27 @@ float Graph:: countCliquesWith(int source, int size){ continue; } vert3 = it3.key(); - qDebug() << "Graph::countCliquesWith() - Possible other neighbor (for 4v clique)" + qDebug() << "Graph::cliquesContaining() - Possible other neighbor (for 4v clique)" << vert3 << "[" << index[vert3] << "]"; if (source == vert3 || vert1 == vert3 || vert2 == vert3 ) { - qDebug() << "Graph::countCliquesWith() - same as source, vert1 or vert2- CONTINUE"; + qDebug() << "Graph::cliquesContaining() - same as source, vert1 or vert2- CONTINUE"; ++it3; continue; } - if ( this->hasEdge( source, vert3 ) == 0 || - this->hasEdge( vert1, vert3 ) == 0 || - this->hasArc ( vert2, vert3 ) == 0 ) { - qDebug() << "Graph::countCliquesWith() - incomplete 4v-subgraph - CONTINUE"; + if ( edgeExists( source, vert3, true) == 0 || + edgeExists( vert1, vert3, true ) == 0 || + edgeExists( vert2, vert3, false ) == 0 ) { + qDebug() << "Graph::cliquesContaining() - incomplete 4v-subgraph - CONTINUE"; ++it3; continue; } quad.clear(); quad << source << vert1 << vert2<< vert3; - qDebug() << "Graph::countCliquesWith() - complete 4v-subgraph " + qDebug() << "Graph::cliquesContaining() - complete 4v-subgraph " << source << "," << vert1 << "," << vert2 << "," << vert3 << " possible (new?) 3-vertex clique: "; - if ( addClique( quad ) ) { - qDebug() << "Graph::countCliquesWith() - 4-vertex cliques " + if ( cliqueAdd( quad ) ) { + qDebug() << "Graph::cliquesContaining() - 4-vertex cliques " << cliques_4_Vertex.count(); } ++it3; @@ -5906,7 +6739,7 @@ float Graph:: countCliquesWith(int source, int size){ } else { - qDebug() << "Graph::countCliquesWith() - Not mutual - CONTINUE"; + qDebug() << "Graph::cliquesContaining() - Not mutual - CONTINUE"; } } ++it2; @@ -5936,26 +6769,30 @@ float Graph:: countCliquesWith(int source, int size){ } + /** - Calculates and returns the total number of cliques in the graph. - Calls countCliquesWith(v1) to calculate the number of cliques of each vertex v1, - sums the total number, then divides it by 3 because each vertex has been counted three times. -*/ -float Graph::countCliquesOfSize(int size){ - qDebug("Graph::countCliquesOfSize()"); + * @brief Graph::cliquesOfSize + * Calculates and returns the total number of cliques in the graph. + * Calls cliquesContaining(v1) to calculate the number of cliques of each vertex v1, + * sums the total number, then divides it by 3 because each vertex has been counted three times. + * @param size + * @return + */ +float Graph::cliquesOfSize(int size){ + qDebug("Graph::cliquesOfSize()"); float cliques=0; QList::const_iterator v1; for (v1=m_graph.cbegin(); v1!=m_graph.cend(); ++v1) { - cliques += countCliquesWith( (*v1) -> name(), size ); + cliques += cliquesContaining( (*v1) -> name(), size ); } cliques = cliques / size; //actually we can just return cliques_*_Vertex.count(); - qDebug() << "Graph::countCliquesOfSize - Dividing by size we get "<< cliques ; + qDebug() << "Graph::cliquesOfSize - Dividing by size we get "<< cliques ; return cliques ; } @@ -5969,30 +6806,34 @@ float Graph::countCliquesOfSize(int size){ float Graph::numberOfTriples(int v1){ float totalDegree=0; if (isSymmetric()){ - totalDegree=outboundEdges(v1); + totalDegree=edgesOutbound(v1); return totalDegree * (totalDegree -1.0) / 2.0; } - totalDegree=outboundEdges(v1) + inboundEdges(v1); //FIXEM + totalDegree=edgesOutbound(v1) + edgesInbound(v1); //FIXEM return totalDegree * (totalDegree -1.0); } + /** - Returns the local clustering coefficient (CLUCOF) of a vertex v1 - CLUCOF in a graph quantifies how close the vertex and its neighbors are - to being a clique, a connected subgraph. - This is used to determine whether a graph is a small-world network. -*/ -float Graph:: localClusteringCoefficient(const long int &v1){ + * @brief Graph::clusteringCoefficientLocal + * Returns the local clustering coefficient (CLUCOF) of a vertex v1 + * CLUCOF in a graph quantifies how close the vertex and its neighbors are + * to being a clique, a connected subgraph. + * This is used to determine whether a graph is a small-world network. + * @param v1 + * @return + */ +float Graph:: clusteringCoefficientLocal(const long int &v1){ if ( !graphModified && (m_graph[ index [v1] ] -> hasCLC() ) ) { float clucof=m_graph[ index [v1] ] ->CLC(); - qDebug() << "Graph::localClusteringCoefficient("<< v1 << ") - " + qDebug() << "Graph::clusteringCoefficientLocal("<< v1 << ") - " << " Not modified. Returning previous clucof = " << clucof; return clucof; } - qDebug() << "Graph::localClusteringCoefficient("<< v1 << ") - " + qDebug() << "Graph::clusteringCoefficientLocal("<< v1 << ") - " << " Graph changed or clucof not calculated."; bool graphSymmetric = false; @@ -6010,11 +6851,11 @@ float Graph:: localClusteringCoefficient(const long int &v1){ H_StrToBool neighborhoodEdges; neighborhoodEdges.clear(); - qDebug() << "Graph::localClusteringCoefficient() - vertex " << v1 + qDebug() << "Graph::clusteringCoefficientLocal() - vertex " << v1 << "[" << index[v1] << "] "; - qDebug () << "Graph::localClusteringCoefficient() - " + qDebug () << "Graph::clusteringCoefficientLocal() - " << " Checking edges adjacent to " << v1; QHash *reciprocalEdges = new QHash; @@ -6029,14 +6870,14 @@ float Graph:: localClusteringCoefficient(const long int &v1){ { u1 = it1.key(); - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " edge with neighbor " << u1 << " [" << index[u1] << "] " << " weight " << it1.value(); if ( v1 == u1 ) { - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " v1 == u1 - CONTINUE"; ++it1; continue; @@ -6048,22 +6889,22 @@ float Graph:: localClusteringCoefficient(const long int &v1){ u2 = it2.key(); - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " cross-checking edge with neighbor " << u2 << " [" << index[u2] << "] " << " weight " << it2.value(); if ( u1 == u2 ) { - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " u1 == u2 - CONTINUE"; ++it2; continue; } - if ( hasArc( u1, u2 ) != 0 ) + if ( edgeExists( u1, u2 ) != 0 ) { - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " connected neighbors: " << u1 << " -> " << u2; @@ -6075,20 +6916,20 @@ float Graph:: localClusteringCoefficient(const long int &v1){ ) { neighborhoodEdges.insert(edge, true); - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " adding edge to neighborhoodEdges "; } else { - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " edge discovered previously... "; } } if ( ! graphSymmetric ) { - if ( hasArc( u2, u1 ) != 0 ) + if ( edgeExists( u2, u1 ) != 0 ) { - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " graph not symmetric " << " connected neighbors: " << u2 << " -> " << u1; @@ -6098,12 +6939,12 @@ float Graph:: localClusteringCoefficient(const long int &v1){ if ( ! neighborhoodEdges.contains(edge) ) { neighborhoodEdges.insert(edge, true); - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " adding edge to neighborhoodEdges "; } else { - qDebug() << "Graph::localClusteringCoefficient() - " + qDebug() << "Graph::clusteringCoefficientLocal() - " << " edge discovered previously... "; } } @@ -6116,7 +6957,7 @@ float Graph:: localClusteringCoefficient(const long int &v1){ nom=neighborhoodEdges.count(); - qDebug() << "Graph::localClusteringCoefficient("<< v1 << ") - " + qDebug() << "Graph::clusteringCoefficientLocal("<< v1 << ") - " << " actual edges in neighborhood " << nom; if ( nom == 0) @@ -6126,7 +6967,7 @@ float Graph:: localClusteringCoefficient(const long int &v1){ k=reciprocalEdges->count(); denom = k * (k -1.0) / 2.0; - qDebug() << "Graph::localClusteringCoefficient("<< v1 << ") - " + qDebug() << "Graph::clusteringCoefficientLocal("<< v1 << ") - " << " symmetric graph. " << " max edges in neighborhood" << denom ; @@ -6137,14 +6978,14 @@ float Graph:: localClusteringCoefficient(const long int &v1){ k=reciprocalEdges->count(); denom = k * (k -1.0); - qDebug() << "Graph::localClusteringCoefficient("<< v1 << ") - " + qDebug() << "Graph::clusteringCoefficientLocal("<< v1 << ") - " << " not symmetric graph. " << " max edges in neighborhood" << denom ; } clucof = nom / denom; - qDebug() << "=== Graph::localClusteringCoefficient("<< v1 << ") - " + qDebug() << "=== Graph::clusteringCoefficientLocal("<< v1 << ") - " << " CLUCOF = "<< clucof; m_graph[ index [v1] ] -> setCLC(clucof); @@ -6155,18 +6996,23 @@ float Graph:: localClusteringCoefficient(const long int &v1){ /** - Calculates local clustering coefficients - and returns the network average Clustering Coefficient -*/ -float Graph::clusteringCoefficient (){ + * @brief Graph::clusteringCoefficient + * Calculates local clustering coefficients and returns + * the network average Clustering Coefficient + * @param updateProgress + * @return + */ +float Graph::clusteringCoefficient (const bool updateProgress){ qDebug("=== Graph::clusteringCoefficient() "); averageCLC=0; maxCLC=0; minCLC=1; float temp=0; + int progressCounter = 0; + Q_UNUSED(progressCounter ); QList::const_iterator vertex; for ( vertex = m_graph.cbegin(); vertex != m_graph.cend(); ++vertex) { - temp = localClusteringCoefficient( (*vertex)->name() ); + temp = clusteringCoefficientLocal( (*vertex)->name() ); if (temp > maxCLC) { maxCLC = temp; maxNodeCLC = (*vertex)->name(); @@ -6176,6 +7022,8 @@ float Graph::clusteringCoefficient (){ minCLC= temp; } averageCLC += temp; + if (updateProgress) + emit updateProgressDialog(++progressCounter); } averageCLC = averageCLC / vertices(); @@ -6186,10 +7034,13 @@ float Graph::clusteringCoefficient (){ -/* + +/** + * @brief Graph::triadCensus * Conducts a triad census and updates QList::triadTypeFreqs, * which is the list carrying all triad type frequencies * Complexity:O(n!) + * @return */ bool Graph::triadCensus(){ int mut=0, asy=0, nul =0; @@ -6264,14 +7115,14 @@ bool Graph::triadCensus(){ qDebug()<< "triad of ("<< ver1 << ","<< ver2 << ","<< ver3 << ") = (" <name() << ","<< vert2->name() << ","<< vert3->name() << ") to m_triad "; @@ -6515,16 +7366,26 @@ int Graph:: factorial(int x) { + /** - Our almost universal network loader. :) - Actually it calls the load() method of parser/qthread class. -*/ + * @brief Graph::loadGraph + * Our almost universal network loader. :) + * Actually it calls the load() method of parser/qthread class. + * @param m_fileName + * @param m_codecName + * @param m_showLabels + * @param maxWidth + * @param maxHeight + * @param fileFormat + * @param two_sm_mode + * @return + */ bool Graph::loadGraph ( const QString m_fileName, const QString m_codecName, const bool m_showLabels, const int maxWidth, const int maxHeight, const int fileFormat, const int two_sm_mode){ - initShowLabels = m_showLabels; + initVertexLabelsVisibility = m_showLabels; qDebug() << "Graph::loadGraph() : "<< m_fileName << " calling parser.load() from thread " << this->thread(); @@ -6555,23 +7416,41 @@ bool Graph::loadGraph ( const QString m_fileName, connect ( file_parser, SIGNAL( addRelation (QString) ), - this, SLOT(addRelationFromParser(QString) ) + this, SLOT(relationAddFromParser(QString) ) ) ; connect ( - file_parser, SIGNAL( changeRelation (int) ), - this, SLOT( changeRelation (int) ) + file_parser, SIGNAL( relationSet (int) ), + this, SLOT( relationSet (int) ) ) ; connect ( - file_parser, SIGNAL( createNode (int,int,QString, QString, int, QString, QString, int, QPointF, QString, bool) ), - this, SLOT(createVertex(int,int,QString, QString, int, QString, QString, int, QPointF, QString, bool) ) + file_parser, SIGNAL( createNode (const int &,const int &, + const QString &, const QString &, + const int&, const QString &, + const QString &, const int&, + const QPointF&, const QString &, + const bool &) ), + this, SLOT( vertexCreate( const int &, const int &, + const QString &, const QString &, + const int &, const QString &, + const QString &, const int &, + const QPointF &, const QString &, + const bool &) ) ) ; connect ( - file_parser, SIGNAL(createEdge (int, int, float, QString, int, bool, bool)), - this, SLOT(createEdge (int, int, float, QString, int, bool, bool) ) + file_parser, SIGNAL( + edgeCreate (const int&, const int&, const float&, + const QString&, const int&, + const bool&, const bool&, + const QString&, const bool&)), + this, SLOT( + edgeCreate (const int&, const int&, const float&, + const QString&, const int&, + const bool&, const bool&, + const QString&, const bool&) ) ); connect ( @@ -6581,7 +7460,7 @@ bool Graph::loadGraph ( const QString m_fileName, connect ( file_parser, SIGNAL(removeDummyNode(int)), - this, SLOT (removeDummyNode(int)) + this, SLOT (vertexRemoveDummyNode(int)) ); connect ( @@ -6599,13 +7478,17 @@ bool Graph::loadGraph ( const QString m_fileName, } +/** + * @brief Graph::terminateParserThreads + * @param reason + */ void Graph::terminateParserThreads(QString reason) { qDebug() << "Graph::terminateParserThreads() - reason " << reason <<" is file_parserThread running? "; if (file_parserThread.isRunning() ) { qDebug() << "Graph::terminateParserThreads() file_parserThread quit"; file_parserThread.quit(); - qDebug() << "Graph::terminateCrawlerThreads() - deleting file_parser pointer"; + qDebug() << "Graph::terminateParserThreads() - deleting file_parser pointer"; delete file_parser; file_parser = 0; // see why here: https://goo.gl/tQxpGA @@ -6613,11 +7496,48 @@ void Graph::terminateParserThreads(QString reason) { } + + + /** - Our almost universal graph saver. :) - Actually it just checks the requested file type and - calls the right saveGraphTo...() method -*/ + * @brief Graph::setFileType + * Updates MW with the file type (0=nofile, 1=Pajek, 2=Adjacency etc) + * Called from Parser when parsing network files. + * @param type + * @param networkName + * @param aNodes + * @param totalLinks + * @param undirected + */ +void Graph::setFileType ( int type, QString netName, + int aNodes, int totalLinks, bool undirected) +{ + qDebug() << "Graph::setFileType() - " + << " type " << type + << " name " << networkName + << " nodes " << aNodes + << " links " << totalLinks + << " undirected " << undirected; + networkName = netName; + m_undirected = undirected; + emit signalFileType (type, networkName, aNodes, totalLinks, m_undirected); + qDebug ()<< "Graph::setFileType() -check parser if running..."; + +} + + +/** + * @brief Graph::saveGraph + * Our almost universal graph saver. :) + * Actually it just checks the requested file type and + * calls the right saveGraphTo...() method + * @param fileName + * @param fileType + * @param networkName + * @param maxWidth + * @param maxHeight + * @return + */ bool Graph::saveGraph ( QString fileName, int fileType, QString networkName, int maxWidth, int maxHeight ) @@ -6695,11 +7615,12 @@ bool Graph::saveGraphToPajekFormat ( for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ for (jt=m_graph.begin(); jt!=m_graph.end(); jt++){ qDebug() << "Graph::saveGraphToPajekFormat: it=" << (*it)->name() << ", jt=" << (*jt)->name() ; - if ( (weight=this->hasArc( (*it)->name(), (*jt)->name())) !=0 - && ( this->hasArc((*jt)->name(), (*it)->name())) == 0 + if ( (weight=edgeExists ( (*it)->name(), (*jt)->name())) !=0 + && ( edgeExists ((*jt)->name(), (*it)->name())) != weight ) { - qDebug()<<"Graph::saveGraphToPajekFormat weight "<< weight << " color "<< (*it)->outLinkColor( (*jt)->name() ) ; + qDebug()<<"Graph::saveGraphToPajekFormat weight "<< weight + << " color "<< (*it)->outLinkColor( (*jt)->name() ) ; t << (*it)->name() <<" "<<(*jt)->name()<< " "<outLinkColor( (*jt)->name() ); @@ -6714,9 +7635,7 @@ bool Graph::saveGraphToPajekFormat ( for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ for (jt=m_graph.begin(); jt!=m_graph.end(); jt++){ qDebug() << "Graph::saveGraphToPajekFormat: it=" << (*it)->name() << ", jt=" <<(*jt)->name() ; - if ( (weight=this->hasArc((*it)->name(), (*jt)->name()))!=0 && - (this->hasArc((*jt)->name(), (*it)->name()))!=0 - ) { + if ( ( weight=edgeExists((*it)->name(), (*jt)->name(), true) )!=0 ) { if ( (*it)->name() > (*jt)->name() ) continue; t << (*it)->name() <<" "<<(*jt)->name()<< " "<isEnabled() ) continue; for (it1=m_graph.cbegin(); it1!=m_graph.cend(); ++it1){ if ( ! (*it1)->isEnabled() ) continue; - if ( (weight = this->hasArc ( (*it)->name(), (*it1)->name() ) ) !=0 ) { + if ( (weight = edgeExists( (*it)->name(), (*it1)->name() ) ) !=0 ) { os << static_cast (weight) << " "; } else @@ -10115,24 +11034,6 @@ void Graph::writeAdjacencyMatrixTo(QTextStream& os){ -/** Outputs adjacency matrix to a text stream -* Used in slotExportSM() of MainWindow class. -*/ -//QTextStream& operator << (QTextStream& os, Graph& m){ -// QList::const_iterator it, it1; -// float weight=-1; -// for (it=m.m_graph.begin(); it!=m.m_graph.end(); it++){ -// for (it1=m.m_graph.begin(); it1!=m.m_graph.end(); it1++){ -// if ( (weight = m.hasArc ( (*it)->name(), (*it1)->name() ) ) !=0 ) { -// os << static_cast (weight) << " "; -// } -// else -// os << "0 "; -// } -// os << endl; -// } -// return os; -//} @@ -10141,7 +11042,7 @@ void Graph::writeAdjacencyMatrixTo(QTextStream& os){ This is called by MainWindow::slotViewAdjacencyMatrix() The resulting matrix HAS NO spaces between elements. */ -void Graph::writeAdjacencyMatrix (const QString fn, const char* netName) { +void Graph::writeAdjacencyMatrix (const QString fn, QString netName) { qDebug()<<"Graph::writeAdjacencyMatrix() to : " << fn; QFile file( fn ); if ( !file.open( QIODevice::WriteOnly ) ) { @@ -10152,14 +11053,15 @@ void Graph::writeAdjacencyMatrix (const QString fn, const char* netName) { outText.setCodec("UTF-8"); int sum=0; float weight=0; - outText << "-Social Network Visualizer- \n"; - outText << "Adjacency matrix of "<< netName<<": \n\n"; + outText << "-Social Network Visualizer "<< VERSION <<"- \n"; + outText << "Network name: "<< ((netName.isEmpty()) ? "Unnamed" : netName )<<" \n"; + outText << "Adjacency matrix: \n\n"; QList::const_iterator it, it1; for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ if ( ! (*it)->isEnabled() ) continue; for (it1=m_graph.cbegin(); it1!=m_graph.cend(); ++it1){ if ( ! (*it1)->isEnabled() ) continue; - if ( (weight = hasArc ( (*it)->name(), (*it1)->name() ) )!=0 ) { + if ( (weight = edgeExists ( (*it)->name(), (*it1)->name() ) )!=0 ) { sum++; outText << (weight) << " "; // TODO make the matrix look symmetric } @@ -10170,7 +11072,7 @@ void Graph::writeAdjacencyMatrix (const QString fn, const char* netName) { } qDebug("Graph: Found a total of %i edge",sum); - if ( sum != enabledEdges() ) qDebug ("Error in edge count found!!!"); + if ( sum != edgesEnabled() ) qDebug ("Error in edge count found!!!"); else qDebug("Edge count OK!"); file.close(); @@ -10181,17 +11083,17 @@ void Graph::writeAdjacencyMatrix (const QString fn, const char* netName) { * Creates an adjacency matrix AM * where AM(i,j)=1 if i is connected to j * and AM(i,j)=0 if i not connected to j - * Used in Graph::centralityInformation() and Graph::invertAdjacencyMatrix() + * Used in Graph::centralityInformation() and Graph::adjacencyMatrixInvert() */ -void Graph::createAdjacencyMatrix(const bool dropIsolates, +void Graph::adjacencyMatrixCreate(const bool dropIsolates, const bool considerWeights, const bool inverseWeights, const bool symmetrize ){ - qDebug() << "Graph::createAdjacencyMatrix()"; + qDebug() << "Graph::adjacencyMatrixCreate()"; float m_weight=-1; int i=0, j=0; if (dropIsolates){ - qDebug() << "Graph::createAdjacencyMatrix() - Find and drop possible isolates"; + qDebug() << "Graph::adjacencyMatrixCreate() - Find and drop possible isolates"; isolatedVertices = verticesIsolated().count(); int m = m_totalVertices-isolatedVertices; AM.resize( m , m); @@ -10199,7 +11101,7 @@ void Graph::createAdjacencyMatrix(const bool dropIsolates, else AM.resize(m_totalVertices, m_totalVertices); QList::const_iterator it, it1; - //qDebug() << "Graph::createAdjacencyMatrix() - creating new adjacency matrix "; + //qDebug() << "Graph::adjacencyMatrixCreate() - creating new adjacency matrix "; for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it){ if ( ! (*it)->isEnabled() || ( (*it)->isIsolated() && dropIsolates) ) { continue; @@ -10209,7 +11111,7 @@ void Graph::createAdjacencyMatrix(const bool dropIsolates, if ( ! (*it1)->isEnabled() || ( (*it1)->isIsolated() && dropIsolates) ) { continue; } - if ( (m_weight = this->hasArc ( (*it)->name(), (*it1)->name() ) ) !=0 ) { + if ( (m_weight = edgeExists ( (*it)->name(), (*it1)->name() ) ) !=0 ) { if (!considerWeights) { AM.setItem(i,j, 1 ); } @@ -10225,7 +11127,7 @@ void Graph::createAdjacencyMatrix(const bool dropIsolates, } qDebug()<<" AM("<< i+1 << ","<< j+1 << ") = " << AM.item(i,j); if (i != j ) { - if ( (m_weight = this->hasArc ( (*it1)->name(), (*it)->name() ) ) !=0 ) { + if ( (m_weight = edgeExists ( (*it1)->name(), (*it)->name() ) ) !=0 ) { if (!considerWeights) AM.setItem(j,i, 1 ); else { @@ -10255,8 +11157,8 @@ void Graph::createAdjacencyMatrix(const bool dropIsolates, } -bool Graph::invertAdjacencyMatrix(const QString &method){ - qDebug()<<"Graph::invertAdjacencyMatrix() "; +bool Graph::adjacencyMatrixInvert(const QString &method){ + qDebug()<<"Graph::adjacencyMatrixInvert() "; bool considerWeights=false; long int i=0, j=0; @@ -10264,7 +11166,7 @@ bool Graph::invertAdjacencyMatrix(const QString &method){ bool dropIsolates=true; // always drop isolates else AM will be singular - createAdjacencyMatrix(dropIsolates, considerWeights); + adjacencyMatrixCreate(dropIsolates, considerWeights); int m = m_totalVertices-isolatedVertices; @@ -10297,11 +11199,11 @@ bool Graph::invertAdjacencyMatrix(const QString &method){ -void Graph::writeInvertAdjacencyMatrix(const QString &fn, +void Graph::writeAdjacencyMatrixInvert(const QString &fn, const QString &netName, const QString &method) { - qDebug("Graph::writeInvertAdjacencyMatrix() "); + qDebug("Graph::writeAdjacencyMatrixInvert() "); int i=0, j=0; QList::const_iterator it, it1; QFile file( fn ); @@ -10311,9 +11213,10 @@ void Graph::writeInvertAdjacencyMatrix(const QString &fn, } QTextStream outText( &file ); outText.setCodec("UTF-8"); - outText << "-Social Network Visualizer- \n"; - outText << "Invert Matrix of network named: "<< netName<< endl; - if (!invertAdjacencyMatrix(method)) { + outText << "-Social Network Visualizer "<< VERSION <<"- \n"; + outText << "Network name: "<< ( (netName.isEmpty()) ? "Unnamed" : netName )<<" \n"; + outText << "Inverse Matrix: \n"; + if (!adjacencyMatrixInvert(method)) { outText << endl<< " The adjacency matrix is singular."; file.close(); return; @@ -10374,7 +11277,7 @@ bool Graph::saveGraphToGraphMLFormat ( qDebug()<< " ... writing xml version"; outText << "name() << "\"?> \n"; - outText << " \n" ; + outText << " \n" ; outText << "" << initEdgeColor << " \n" " \n"; + outText << " \n" + " " << ""<< " \n" + " \n"; + qDebug()<< " ... writing graph tag"; if (networkName == "") networkName = "G"; - if (m_undirected) + if (isUndirected()) outText << " \n"; else outText << " \n"; @@ -10492,46 +11399,99 @@ bool Graph::saveGraphToGraphMLFormat ( qDebug() << " ... writing edges data"; edgeCount=0; - for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it) - { - for (jt=m_graph.begin(); jt!=m_graph.end(); jt++) + if (!isUndirected()) { + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it) { - source=(*it)->name(); - target=(*jt)->name(); - - if ( (weight= this->hasArc( source,target ) ) !=0 ) + for (jt=m_graph.begin(); jt!=m_graph.end(); jt++) { - ++edgeCount; - m_color = (*it)->outLinkColor( target ); - qDebug()<< " edge no "<< edgeCount - << " from n1=" << source << " to n2=" << target - << " with weight " << weight - << " and color " << m_color.toUtf8() ; - outText << " 1) { - outText << "> \n"; - outText << " " << weight<<"" <<" \n"; - openToken=false; - } - if ( QString::compare ( initEdgeColor, m_color, Qt::CaseInsensitive) != 0) { - if (openToken) + source=(*it)->name(); + target=(*jt)->name(); + m_label = ""; + if ( (weight= edgeExists( source,target ) ) !=0 ) + { + ++edgeCount; + m_color = (*it)->outLinkColor( target ); + m_label = edgeLabel(source, target); + qDebug()<< " edge no "<< edgeCount + << " from n1=" << source << " to n2=" << target + << " with weight " << weight + << " and color " << m_color.toUtf8() ; + outText << " \n"; - outText << " " << m_color <<"" <<" \n"; - openToken=false; + outText << " " << weight<<"" <<" \n"; + openToken=false; + } + if ( QString::compare ( initEdgeColor, m_color, Qt::CaseInsensitive) != 0) { + if (openToken) + outText << "> \n"; + outText << " " << m_color <<"" <<" \n"; + openToken=false; + } + if ( !m_label.isEmpty()) { + if (openToken) + outText << "> \n"; + outText << " " << m_label<<"" <<" \n"; + openToken=false; + } + + if (openToken) + outText << "/> \n"; + else + outText << " \n"; + } - if (openToken) - outText << "/> \n"; - else - outText << " \n"; } + } + } + else { + for (it=m_graph.cbegin(); it!=m_graph.cend(); ++it) + { + for (jt=it; jt!=m_graph.end(); jt++) + { + source=(*it)->name(); + target=(*jt)->name(); + + if ( (weight= edgeExists( source,target, true ) ) !=0 ) + { + ++edgeCount; + m_color = (*it)->outLinkColor( target ); + qDebug()<< " edge no "<< edgeCount + << " from n1=" << source << " to n2=" << target + << " with weight " << weight + << " and color " << m_color.toUtf8() ; + outText << " \n"; + outText << " " << weight<<"" <<" \n"; + openToken=false; + } + if ( QString::compare ( initEdgeColor, m_color, Qt::CaseInsensitive) != 0) { + if (openToken) + outText << "> \n"; + outText << " " << m_color <<"" <<" \n"; + openToken=false; + } + if (openToken) + outText << "/> \n"; + else + outText << " \n"; + + } + } } } + outText << " \n"; outText << "\n"; @@ -10546,76 +11506,15 @@ bool Graph::saveGraphToGraphMLFormat ( -void Graph::setShowLabels(bool toggle){ - initShowLabels=toggle; - -} - -void Graph::setShowNumbersInsideNodes(bool toggle){ - initNumbersInsideNodes=toggle; - -} - - - - - -/** - This slot is activated when the user clicks on the relevant MainWindow checkbox - (SpringEmbedder, Fruchterman) - to start or stop the movement of nodes, according to the requested model. - PARAMETERS: - state: movement on/off toggle - type: controls the type of layout model requested. Available options - 1: Spring Embedder - 2: FruchtermanReingold - cW, cH: control the current canvasWidth and canvasHeight -*/ -void Graph::nodeMovement(bool state, int type, int cW, int cH){ - qDebug()<< "Graph: startNodeMovement() - state " << state; - canvasWidth = cW; - canvasHeight = cH; - //factor controls speed. Decrease it to increase speed... - // the smaller the factor is, the less responsive is the application - // when there are many nodes. - int factor=50; - if (state == true){ - qDebug()<< "Graph: startNodeMovement() - STARTING dynamicMovement" ; - dynamicMovement = true; - layoutType=type; - if (!timerId) { - qDebug("Graph: startTimer()"); - timerId = startTimer(factor); - } - } - else { - qDebug()<< "Graph: startNodeMovement() - STOPPING dynamicMovement" ; - dynamicMovement = false; - killTimer(timerId); - timerId = 0; - } -} - - /** This method is automatically invoked when a QTimerEvent occurs - It checks layoutType to call the appropriate method with the Force Directed Placement algorithm. + UNUSED */ void Graph::timerEvent(QTimerEvent *event) { qDebug("Graph: timerEvent()"); Q_UNUSED(event); - switch (layoutType){ - case 1: { - layoutForceDirectedSpringEmbedder(dynamicMovement); - break; - } - case 2: { - layoutForceDirectedFruchtermanReingold(dynamicMovement); - break; - } - } if (!graphModified) { qDebug("Timer will be KILLED since no vertex is movin any more..."); killTimer(timerId); @@ -10626,8 +11525,11 @@ void Graph::timerEvent(QTimerEvent *event) { -/** - The Spring Embedder model (Eades, 1984), part of the Force Directed Placement (FDP) family, + +/** + * @brief Graph::layoutForceDirectedSpringEmbedder + * @param maxIterations + * The Spring Embedder model (Eades, 1984), part of the Force Directed Placement (FDP) family, assigns forces to all vertices and edges, as if nodes were electrically charged particles (Coulomb's law) and all edges were springs (i.e. Hooke's law). @@ -10638,32 +11540,36 @@ void Graph::timerEvent(QTimerEvent *event) { we can -and we do- apply unrealistic forces in an unrealistic manner. For instance, instead of the forces described by Hooke's law, we will assume weaker logarithmic forces between far apart vertices... -*/ + */ +void Graph::layoutForceDirectedSpringEmbedder(const int maxIterations){ -void Graph::layoutForceDirectedSpringEmbedder(bool &dynamicMovement){ + int progressCounter=0; qreal dist = 0; qreal f_rep=0, f_att=0; QPointF DV; qreal c4=0.1; //normalization factor for final displacement + QList::const_iterator v1; QList::const_iterator v2; + /* apply an inital random layout */ + layoutRandom(); + /** * compute max spring length as function of canvas area divided by the * total vertices area */ qreal V = (qreal) vertices() ; qreal naturalLength= computeOptimalDistance(V); - qDebug() << "\n\n layoutForceDirectedSpringEmbedder() " << " vertices " << V << " naturalLength " << naturalLength; - if (dynamicMovement){ + int iteration = 1 ; + for ( iteration=1; iteration <= maxIterations ; iteration++) { //setup init disp - for (v1=m_graph.cbegin(); v1!=m_graph.cend(); ++v1) { (*v1) -> disp().rx() = 0; @@ -10697,13 +11603,13 @@ void Graph::layoutForceDirectedSpringEmbedder(bool &dynamicMovement){ DV.setX( (*v2) -> x() - (*v1)->x()); DV.setY( (*v2) -> y() - (*v1)->y()); - dist = euclideian_distance(DV); + dist = length(DV); /** * calculate electric (repulsive) forces between * all vertices. */ - f_rep = layoutForceDirected_F_rep (dist, naturalLength) ; + f_rep = layoutForceDirected_F_rep ("Eades", dist, naturalLength) ; (*v1)->disp().rx() += sign( DV.x() ) * f_rep ; (*v1)->disp().ry() += sign( DV.y() ) * f_rep ; qDebug() <<" s = "<< (*v1)->name() @@ -10718,9 +11624,9 @@ void Graph::layoutForceDirectedSpringEmbedder(bool &dynamicMovement){ * that pull them together (if d > naturalLength) * or push them apart (if d < naturalLength) */ - if ( this->hasArc ( (*v1) ->name(), (*v2) -> name()) ) { + if ( this->edgeExists( (*v1) ->name(), (*v2) -> name()) ) { - f_att = layoutForceDirected_F_att (dist, naturalLength) ; + f_att = layoutForceDirected_F_att ("Eades", dist, naturalLength) ; (*v1)->disp().rx() += sign( DV.x() ) * f_att ; (*v1)->disp().ry() += sign( DV.y() ) * f_att ; @@ -10738,11 +11644,10 @@ void Graph::layoutForceDirectedSpringEmbedder(bool &dynamicMovement){ << " disp_t.x="<< (*v2)->disp().rx() << " disp_t.y="<< (*v2)->disp().ry(); - } // end if hasArc + } // end if edgeExists } //end for v2 - //recompute naturalLength (in case the user resized the window) - naturalLength= computeOptimalDistance(V); + qDebug() << " >>> final s = "<< (*v1)->name() << " disp_s.x="<< (*v1)->disp().rx() << " disp_s.y="<< (*v1)->disp().ry(); @@ -10752,92 +11657,105 @@ void Graph::layoutForceDirectedSpringEmbedder(bool &dynamicMovement){ layoutForceDirected_Eades_moveNodes(c4) ; - } //end dynamicMovement + progressCounter++; + emit updateProgressDialog(progressCounter ); + + } //end iterations } + /** - Fruchterman and Reingold (1991) refined the Spring Embedder model by replacing the forces. + * @brief Graph::layoutForceDirectedFruchtermanReingold + * @param maxIterations + * Fruchterman and Reingold (1991) refined the Spring Embedder model by replacing the forces. In this model, "the vertices behave as atomic particles or celestial bodies, exerting attractive and repulsive forces on one another." (ibid). Again, only vertices that are neighbours attract each other but, unlike Spring Embedder, all vertices repel each other. These forces induce movement. The algorithm might resemble molecular or planetary simulations, sometimes called n-body problems. -*/ -void Graph::layoutForceDirectedFruchtermanReingold(bool dynamicMovement){ + */ +void Graph::layoutForceDirectedFruchtermanReingold(const int maxIterations){ + int progressCounter=0; qreal dist = 0; qreal f_att, f_rep; QPointF DV; //difference vector //qreal temperature=canvasWidth / 10.0; //limits the displacement of the vertex - qreal temperature=2.0; //limits the displacement of the vertex + //qreal temperature=5.8309518948453; //limits the displacement of the vertex qreal V = (qreal) vertices() ; qreal C=0.9; //this is found experimentally // optimalDistance (or k) is the radius of the empty area around a vertex - // we add vertexWidth to it qreal optimalDistance= C * computeOptimalDistance(V); + + /* apply an inital random layout */ + layoutRandom(); + + qDebug() << "Graph: layoutForceDirectedFruchtermanReingold() "; + qDebug () << "Graph: Setting optimalDistance = "<< optimalDistance + << "...following Fruchterman-Reingold (1991) formula "; + + qDebug() << "Graph: canvasWidth " << canvasWidth << " canvasHeight " << canvasHeight; QList::const_iterator v1; QList::const_iterator v2; - - if (dynamicMovement){ - qDebug() << "Graph: layoutForceDirectedFruchtermanReingold() "; - qDebug () << "Graph: Setting optimalDistance = "<< optimalDistance - << "...following Fruchterman-Reingold (1991) formula "; + int iteration = 1 ; + for ( iteration=1; iteration <= maxIterations ; iteration++) { //setup init disp for (v1=m_graph.cbegin(); v1!=m_graph.cend(); ++v1) { (*v1)->disp().rx() = 0; (*v1)->disp().ry() = 0; - qDebug() << " 0000 s " << (*v1)->name() << " zeroing rx/ry"; + //qDebug() << " 0000 s " << (*v1)->name() << " zeroing rx/ry"; } for (v1=m_graph.cbegin(); v1!=m_graph.cend(); ++v1) { - qDebug() << "***** Calculate forces for s " << (*v1)->name() - << " index " << index[(*v1)->name()] - << " pos "<< (*v1)->x() << ", "<< (*v1)->y(); +// qDebug() << "***** Calculate forces for s " << (*v1)->name() +// << " index " << index[(*v1)->name()] +// << " pos "<< (*v1)->x() << ", "<< (*v1)->y(); if ( ! (*v1)->isEnabled() ) { - qDebug() << " vertex s " << (*v1)->name() << " disabled. Continue"; +// qDebug() << " vertex s " << (*v1)->name() << " disabled. Continue"; continue; } for (v2=m_graph.cbegin(); v2!=m_graph.cend(); ++v2) { - qDebug () << " t = "<< (*v2)->name() - << " pos (" << (*v2)->x() << "," << (*v2)->y() << ")"; +// qDebug () << " t = "<< (*v2)->name() +// << " pos (" << (*v2)->x() << "," << (*v2)->y() << ")"; if ( ! (*v2)->isEnabled() ) { - qDebug()<< " t "<< (*v2)->name()<< " disabled. Continue"; +// qDebug()<< " t "<< (*v2)->name()<< " disabled. Continue"; continue; } if (v2 == v1) { - qDebug() << " s==t, continuing"; +// qDebug() << " s==t, continuing"; continue; } DV.setX( (*v2)->x() - (*v1)->x() ); DV.setY( (*v2)->y() - (*v1)->y() ); - dist = euclideian_distance( DV ); + dist = length( DV ); //calculate repulsive force from _near_ vertices - f_rep = layoutForceDirected_F_rep(dist, optimalDistance); + f_rep = layoutForceDirected_F_rep( "FR", dist, optimalDistance); (*v1)->disp().rx() += sign( DV.x() ) * f_rep; (*v1)->disp().ry() += sign( DV.y() ) * f_rep ; - qDebug()<< " dist( " << (*v1)->name() << "," << (*v2)->name() << " = " - << dist - << " f_rep " << f_rep - << " disp_s.x="<< (*v1)->disp().rx() - << " disp_s.y="<< (*v1)->disp().ry(); +// qDebug()<< " dist( " << (*v1)->name() << "," << (*v2)->name() << " = " +// << dist +// << " f_rep " << f_rep +// << " disp_s.x="<< (*v1)->disp().rx() +// << " disp_s.y="<< (*v1)->disp().ry(); - if ( this->hasArc ((*v1)->name(), (*v2)->name()) ) { + if ( edgeExists ((*v1)->name(), (*v2)->name()) ) { //calculate attracting force - f_att = layoutForceDirected_F_att (dist, optimalDistance); + f_att = layoutForceDirected_F_att ("FR", dist, optimalDistance); (*v1)->disp().rx() += sign( DV.x() ) * f_att; (*v1)->disp().ry() += sign( DV.y() ) * f_att; (*v2)->disp().rx() -= sign( DV.x() ) * f_att ; @@ -10854,20 +11772,79 @@ void Graph::layoutForceDirectedFruchtermanReingold(bool dynamicMovement){ } //endif }//end for v2 - //recompute optimalDistance (in case the user resized the window) - optimalDistance= C * computeOptimalDistance(V); + } //end for v1 - layoutForceDirected_FR_moveNodes(temperature); + // limit the max displacement to the temperature t + // prevent placement outside of the frame/canvas + layoutForceDirected_FR_moveNodes( layoutForceDirected_FR_temperature (iteration) ); - // reduce the temperature as the layout approaches a better configuration - //cool(temperature); + progressCounter++; + emit updateProgressDialog(progressCounter ); } } + +/** + * @brief Graph::layoutForceDirectedKamadaKawai + * In this model, the graph is considered to be a dynamic system + * where every two vertices are connected by a 'spring' of a + * desirable length, which corresponds to their graph theoretic + * distance. In this way, the optimal layout of the graph + * is the state with the minimum imbalance. The degree of + * imbalance is formulated as the total spring energy: + * the square summation of the differences between desirable + * distances and real ones for all pairs of vertices + * @return qreal temperature + */ + +void Graph::layoutForceDirectedKamadaKawai(const int maxIterations){ + Q_UNUSED(maxIterations); + // compute dij for 1 <= i!=j <= n + + // compute lij for 1 <= i!=j <= n + + // compute kij for 1 <= i!=j <= n + + // initialize p1, p2, ... pn; + + // while ( max_D_i > e ) + + // let pm the particle satisfying D_m = max_D_i + + // while ( D_m > e) + + // compute delta_x and delta_y by solving equations 11 and 12 + // x_m = x_m + delta_x + // y_m = y_m + delta_y + + + +} + +/** + * @brief Graph::layoutForceDirected_FR_temperature + * Reduces the temperature as the layout approaches a better configuration + * @return qreal temperature + */ +qreal Graph::layoutForceDirected_FR_temperature(const int iteration) const{ + qreal temp=0; + qDebug() << "Graph::layoutForceDirected_FR_temperature(): cool iteration " << iteration; + if (iteration < 10) + temp =canvasWidth / 10.0; + else + temp =canvasWidth / (iteration + 10) ; + if (iteration > 100) // follow Eades advice... + temp = 0; + qDebug() << "Graph::layoutForceDirected_FR_temperature() - iteration " << iteration + << " temp " << temp; + return temp; + +} + /** * @brief Graph::computeOptimalDistance * @return qreal optimalDistance @@ -10886,13 +11863,14 @@ qreal Graph::computeOptimalDistance(const int &Vertices){ -qreal Graph::layoutForceDirected_F_att( const qreal &dist, const qreal &optimalDistance) { +qreal Graph::layoutForceDirected_F_att( const QString model, const qreal &dist, + const qreal &optimalDistance) { qreal f_att; - if (layoutType == 1) { //layoutType -> Eades + if (model == "Eades") { qreal c_spring=2; f_att = c_spring * log10 ( dist / optimalDistance ); } - else { // layoutType -> FR + else { // model -> FR f_att= ( dist * dist ) / optimalDistance; } @@ -10900,9 +11878,10 @@ qreal Graph::layoutForceDirected_F_att( const qreal &dist, const qreal &optimalD } -qreal Graph::layoutForceDirected_F_rep(const qreal &dist, const qreal &optimalDistance) { +qreal Graph::layoutForceDirected_F_rep( const QString model, const qreal &dist, + const qreal &optimalDistance) { qreal f_rep; - if (layoutType == 1) { //layoutType -> Eades + if (model == "Eades") { if (dist !=0){ qreal c_rep= 1.0; f_rep = c_rep / (dist * dist); @@ -10916,7 +11895,8 @@ qreal Graph::layoutForceDirected_F_rep(const qreal &dist, const qreal &optimalDi } } - else { // layoutType -> FR + else { // model -> FR + // To speed up our algorithm we use the grid-variant algorithm. if ( (2.0 * optimalDistance) < dist ) { //neglect vertices outside circular area of radius 2*optimalDistance f_rep=0; @@ -10985,12 +11965,12 @@ void Graph::compute_angles(const QPointF &DV, /** - * @brief Graph::euclideian_distance + * @brief Graph::length * @param a * @param b * @return the euclideian distance of QPointF a and b */ -qreal Graph::euclideian_distance (const QPointF & a, const QPointF & b){ +qreal Graph::length (const QPointF & a, const QPointF & b){ return qSqrt ( ( b.x() - a.x() ) * (b.x() - a.x() ) + ( b.y() - a.y()) * (b.y() - a.y() ) @@ -10999,11 +11979,11 @@ qreal Graph::euclideian_distance (const QPointF & a, const QPointF & b){ /** - * @brief Graph::euclideian_distance + * @brief Graph::length * @param a * @return the euclideian distance of QPointF a (where a is difference vector) */ -qreal Graph::euclideian_distance (const QPointF & a){ +qreal Graph::length (const QPointF & a){ return qSqrt ( a.x() * a.x() + a.y() * a.y() @@ -11028,8 +12008,10 @@ void Graph::layoutForceDirected_Eades_moveNodes(const qreal &c4) { //fix Qt error a positive QPoint to the floor // when we ask for moveNode to happen. - xvel < 1 && xvel > 0 ? xvel = 1 : xvel = xvel; - yvel < 1 && yvel > 0 ? yvel = 1 : yvel = yvel; + if ( xvel < 1 && xvel > 0 ) + xvel = 1 ; + if ( yvel < 1 && yvel > 0 ) + yvel = 1 ; //Move source node to new position according to overall velocity newPos = QPointF( (qreal) (*v1)->x() + xvel, (qreal) (*v1)->y() + yvel); @@ -11042,13 +12024,12 @@ void Graph::layoutForceDirected_Eades_moveNodes(const qreal &c4) { // check if new pos is out of screen and adjust newPos.rx() = qMin ( - canvasWidth - 42.0 , qMax (42.0 , newPos.x() ) + canvasWidth - 50.0 , qMax (50.0 , newPos.x() ) ); newPos.ry() = qMin ( - canvasHeight -42.0 , qMax (42.0 , newPos.y() ) + canvasHeight -50.0 , qMax (50.0 , newPos.y() ) ); - qDebug() << " Final new pos (" << newPos.x() << "," << newPos.y()<< ")"; emit moveNode((*v1)->name(), newPos.x(), newPos.y()); @@ -11064,6 +12045,7 @@ void Graph::layoutForceDirected_Eades_moveNodes(const qreal &c4) { void Graph::layoutForceDirected_FR_moveNodes(const qreal &temperature) { qDebug() << "\n\n ***** layoutForceDirected_FR_moveNodes() \n\n " ; + qDebug () << " temperature " << temperature; QPointF newPos; qreal xvel = 0, yvel = 0; QList::const_iterator v1; @@ -11081,18 +12063,12 @@ void Graph::layoutForceDirected_FR_moveNodes(const qreal &temperature) { << newPos.y()<< ")"; newPos.rx() = qMin ( - canvasWidth - 42.0 , qMax (42.0 , newPos.x() ) + canvasWidth - 50.0 , qMax (50.0 , newPos.x() ) ); newPos.ry() = qMin ( - canvasHeight -42.0 , qMax (42.0 , newPos.y() ) + canvasHeight -50.0 , qMax (50.0 , newPos.y() ) ); //Move node to new position - if ( newPos.x() < 5.0 ||newPos.y() < 5.0 || - newPos.x() >= (canvasWidth -5)|| - newPos.y() >= (canvasHeight-5)|| - ((*v1)->x() == newPos.x() && (*v1)->y() == newPos.y() ) - ) - continue; qDebug()<< " final new pos " << newPos.x() << "," << newPos.y()<< ")"; diff --git a/src/graph.h b/src/graph.h index e9c4bc78..40382cfc 100755 --- a/src/graph.h +++ b/src/graph.h @@ -5,7 +5,7 @@ graph.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -45,19 +45,15 @@ #include "parser.h" #include "webcrawler.h" -using namespace std; - -class QPointF; +static const int EDGE_DIRECTED = 0; +static const int EDGE_DIRECTED_OPPOSITE_EXISTS = 1; +static const int EDGE_RECIPROCAL_UNDIRECTED = 2; -/** This is the main class for a Graph, used in conjuction with Vertex, Parser and Matrix objects. +using namespace std; - Graph class has the interface and the various network algorithms - Vertex class holds each vertex data (colors, strings, statistics, etc) - Matrix class holds the adjacency matrix of the network. - Parser class loads files of networks. -*/ +class QPointF; typedef QList Vertices; @@ -71,7 +67,6 @@ typedef QHash H_StrToBool; - class Distance { public: @@ -106,58 +101,79 @@ class CompareDistances { +// TODO & KNOWN BUGS: +// - Execute all options/commands from MW and propagate them to GW via signals +// - BUG: wrong default edge colors (not the ones used by Settings) after loading GraphML files. +// - BUG: Resizing the MW view does not resize/reposition the layout guides +// - BUG: Fruchterman-Reingold model fixes some nodes to (1,1) breaking the layout +// - TODO: Enrich Node properties dialog +// - BUG: Rubber band selection does not always work on large nets where nodes been removed. + + +/** + * @brief The Graph class + * This is the main class for a Graph, used in conjuction with Vertex, Parser and Matrix objects. + * Graph class methods are the interface to various analysis algorithms + * Vertex class holds each vertex data (colors, strings, statistics, etc) + * Matrix class holds the adjacency matrix of the network. + * Parser class loads files of networks. + */ class Graph: public QObject{ Q_OBJECT QThread file_parserThread; QThread wc_parserThread; QThread wc_spiderThread; public slots: - int currentRelation(); + int relationCurrent(); /** Slots to signals from Parser */ - void addRelationFromParser(QString); - void createVertex( int i, int size, QString nodeColor, - QString numColor, int numSize, - QString label, QString lColor, int lSize, - QPointF p, QString nodeShape, bool signalMW + void relationAddFromParser(QString); + void vertexCreate(const int &num, const int &size, const QString &nodeColor, + const QString &numColor, const int &numSize, + const QString &label, const QString &lColor, + const int &labelSize, const QPointF &p, const QString &nodeShape, + const bool &signalMW );//Main vertex creation call - void setFileType(int, QString, int,int, bool); - void removeDummyNode(int); + void setFileType(int, QString netName, int, int, bool); + void vertexRemoveDummyNode(int); void terminateParserThreads (QString reason); /** Slots to signals from GraphicsWidget and Parser*/ - void createEdge (int, int, float, QString, int, bool, bool); //GW and Parser. - void createEdge (int, int, float, int, bool, bool); //GW - void createEdgeWebCrawler (int, int); //WebCrawler - void nodeMovement(bool state, int type, int cW, int cH); //Called by MW to start movement + void edgeCreate (const int &v1, const int &v2, const float &weight, + const QString &color , + const int &type=0, + const bool &drawArrows=true, const bool &bezier=false, + const QString &label=QString::null, + const bool &signalMW=true); + void edgeCreateWebCrawler (const int &source, const int &target); - void slotSetEdgeVisibility(int relation, int, int, bool); + void edgeVisibilitySet(int relation, int, int, bool); - //auxiliary createVertex functions - void createVertex(int i, QPointF p); //Called by GW - void createVertex(int i, int canvasWidth, int canvasHeight); //Called by MW - void createVertexWebCrawler(QString label, int i) ; + //auxiliary vertexCreate functions + void vertexCreate(const QPointF &p); + void vertexCreate(int i); + void vertexCreateWebCrawler(const QString &label, const int &i) ; /** Slots to signals from MainWindow */ - void changeRelation(int); - void addRelationFromUser(QString relation); - void setCanvasDimensions(int w, int h); - void filterIsolateVertices ( bool ); //Called by MW to filter orphan vertices - void filterEdgesByWeight (float, bool); //Called by MW to filter edges over/under a weight - void filterEdgesByRelation(int relation, bool status); + void relationSet(int); + void relationAddFromUser(QString relation); + void canvasSizeSet(const int w, const int h); + double canvasMinDimension() const; + void vertexIsolateFilter ( bool ); //Called by MW to filter orphan vertices + void edgeFilterByWeight (float, bool); //Called by MW to filter edges over/under a weight + void edgeFilterByRelation(int relation, bool status); void webCrawl(QString, int, int, bool extLinks, bool intLinks); //Called by MW to start a web crawler... - void setGraphChanged(bool changed) { graphModified = changed; } signals: /** Signals to MainWindow */ void updateProgressDialog(int ); - void graphChanged(); //call to update MW widgets + void graphChanged(); //call to update MW widgets void signalFileType (int, QString, int,int, bool); //notifies MW what we have loaded. void statusMessage (QString message); //updates statusbar message @@ -167,23 +183,45 @@ public slots: void signalNodeSizesByInDegree(bool); /** Signals to GraphicsWidget */ - void drawNode( int ,int, QString, QString, int, QString, QString, int, - QPointF, QString, bool, bool, bool); //call GW to draw a node + void drawNode( const int &num, const int &size, const QString &nodeShape, + const QString &nodeColor, + const bool &showNumbers,const bool &numbersInside, + const QString &numberColor, const int &numSize, + const bool &showLabels, const QString &label, + const QString &labelColor, const int &labelSize, + const QPointF &p + ); void eraseNode (long int); //erase node from GW - void drawEdge(int, int, float, bool, bool, QString, bool); //call GW to draw an edge - void eraseEdge(int, int); //emited from removeEdge() to GW to clear the edge item. + //call GW to draw an edge + void drawEdge ( const int &v1, const int &v2, const float &weight, + const QString &label="", + const QString &color="black", + const int &type=0, const bool arrows=true, + const bool &bezier=false, const bool &weightNumbers=false); + void eraseEdge(const long int &, const long int &); //emited from edgeRemove() to GW to clear the edge item. void setEdgeVisibility (int, int, int, bool); // emitted from each Vertex void setVertexVisibility(long int, bool); //notifies GW to disable a node - void setNodeSize(long int, int); - void setNodeShape(const long int, const QString); - void setNodeColor(long int, QString); + void setNodeSize(const long int &v, const int &size); + void setNodeShape(const long int v, const QString &shape); + void setNodeColor(const long int v, const QString &color); void setNodeLabel(long int, QString); - void drawEdgeReciprocal(int, int); //call GW to draw the edge as symmetric one - void changeEdgeColor(long int, long int, QString); - void addGuideCircle(int, int, int); //call GW to draw a circular layout line somewhere. - void addGuideHLine (int); //call GW to draw a horizontal layout line somewhere. - void moveNode(int, qreal, qreal); + void setNodeNumberSize(const long int &, const int &); + void setNodeNumberDistance(const long int &, const int &); + void setNodeLabelSize(const long int &, const int &); + void setNodeLabelDistance(const long int &, const int &); + + void setEdgeWeight (const long int &v1, const long int &v2, const float &weight); + void setEdgeUndirected(const long int &v1, const long int &v2, const float &weight); + void setEdgeColor(const long int &v1, + const long int &v2, + const QString &color); + void setEdgeLabel (const long int &v1, + const long int &v2, + const QString &label); + void addGuideCircle(const double&, const double&, const double&); + void addGuideHLine (const double&y0); + void moveNode(const int &, const qreal &, const qreal &); /** Signals to Vertice */ void relationChanged(int); @@ -200,8 +238,6 @@ public slots: void setSocNetV_Version (QString ver) { VERSION = ver; } - void setShowLabels(bool toggle); - void setShowNumbersInsideNodes(bool toggle); /*FILES (READ AND WRITE)*/ bool loadGraph (const QString, const QString m_codecName, @@ -219,49 +255,65 @@ public slots: bool saveGraphToDotFormat (QString fileName, QString networkName, int maxWidth, int maxHeight); bool saveGraphToGraphMLFormat (QString fileName,QString networkName, int maxWidth, int maxHeight); + /* RELATIONS */ + int relations(); + void relationAddFromGraph(QString relationName); + + /* VERTICES */ - int lastVertexNumber(); - int firstVertexNumber(); + int vertexLastNumber(); + int vertexFirstNumber(); - int hasVertex(long int ); - int hasVertex(QString); - void removeVertex (long int ); + int vertexDegreeOut(int); + int vertexDegreeIn(int); - void setInitVertexSize (const long int); - void setVertexSize(const long int &v, const int &newsize ); - void setAllVerticesSize(const int &newsize); + int vertexExists(const long int &v1 ); + int vertexExists(const QString &label); + void vertexRemove (long int ); + + void vertexSizeInit (const long int); + void vertexSizeSet(const long int &v, const int &newsize ); + void vertexSizeAllSet(const int newsize); int vertexSize(const long int &v); - void setInitVertexShape (const QString); - void setVertexShape(const int v, const QString shape); - void setAllVerticesShape(const QString shape); + void vertexShapeInit (const QString); + void vertexShapeSet(const int v, const QString shape); + void vertexShapeAllSet(const QString shape); QString vertexShape(const int &v); - void setInitVertexColor (const QString &color); - void setVertexColor(const long &v, const QString &color); - void setAllVerticesColor(const QString &color); + void vertexColorInit (const QString &color); + void vertexColorSet(const long &v, const QString &color); + void vertexColorAllSet(const QString &color); QColor vertexColor(const long int &v); - void setInitVertexNumberColor ( QString color); - void setInitVertexNumberSize (int size); - - void setInitVertexLabelSize(int newSize); - void setVertexLabelSize(int v, int newSize); - - void setInitVertexLabelColor(QString color); - void setVertexLabel(int v, QString label); - void setVertexLabelColor(int v1, QString color); + void vertexNumberColorInit ( QString color); + void vertexNumberSizeInit (const int &size); + void vertexNumberSizeSet(const long int &v, const int &newsize ); + void vertexNumberSizeSetAll (const int &size); + void vertexNumberDistanceInit (const int &distance); + void vertexNumberDistanceSet(const long int &v, const int &newDistance ); + void vertexNumberDistanceSetAll (const int &newDistance); + void vertexNumbersInsideNodesSet(bool toggle); + void vertexNumbersVisibilitySet(bool toggle); + + void vertexLabelsVisibilitySet(bool toggle); + void vertexLabelSizeInit(int newSize); + void vertexLabelSizeSet(const long int &v, const int &newsize ); + void vertexLabelSizeAllSet (const int &); + void vertexLabelColorInit(QString color); + void vertexLabelSet(int v, QString label); + void vertexLabelColorSet(int v1, QString color); QString vertexLabel(const long int &v1); + void vertexLabelDistanceInit (const int &distance); + void vertexLabelDistanceSet(const long int &v, const int &newDistance ); + void vertexLabelDistanceAllSet (const int &newDistance); - void updateVertCoords(int v, int x, int y); + void vertexPosSet(const int &v, const int &x, const int &y); int vertices(const bool dropIsolates=false, const bool countAll=false) ; - int outboundEdges (int i) ; - int inboundEdges (int i) ; - - int outDegree(int); - int inDegree(int); + int edgesOutbound (int i) ; + int edgesInbound (int i) ; int verticesWithOutboundEdges(); int verticesWithInboundEdges(); @@ -269,16 +321,19 @@ public slots: QList verticesIsolated(); - qreal euclideian_distance(const QPointF &a, const QPointF &b); - qreal euclideian_distance(const QPointF &a); + qreal length(const QPointF &a, const QPointF &b); + qreal length(const QPointF &a); int sign(const qreal &D); - qreal layoutForceDirected_F_rep(const qreal &dist,const qreal &optimalDistance) ; - qreal layoutForceDirected_F_att(const qreal &dist,const qreal &optimalDistance) ; + qreal layoutForceDirected_F_rep(const QString model, const qreal &dist, + const qreal &optimalDistance) ; + qreal layoutForceDirected_F_att(const QString model, const qreal &dist, + const qreal &optimalDistance) ; void layoutForceDirected_Eades_moveNodes(const qreal &c4); void layoutForceDirected_FR_moveNodes(const qreal &temperature) ; + qreal layoutForceDirected_FR_temperature(const int iteration) const; qreal computeOptimalDistance(const int &Vertices); void compute_angles( const QPointF &Delta, const qreal &dist, @@ -288,48 +343,59 @@ public slots: qreal °rees2 ); /* EDGES */ - int enabledEdges(); - void edges(); - float hasArc (const long &v1, const long &v2); - bool hasEdge (const int &v1, const long int &v2); - void removeEdge (int v1, int v2); + int edgesEnabled(); + float edgeExists(const long &v1, const long &v2, const bool &undirected=false); - bool isWeighted(); + void edgeRemove (const long int &v1, const long int &v2, const bool &undirected=false); + bool edgeSymmetric(const long &v1, const long &v2); + void edgeUndirectedSet(const long int &v1, const long int &v2, const float &w); + + void edgeWeightSet (const long int &v1, const long int &v2, + const float &w, + const bool &undirected=false); + float edgeWeight(const long int &v1, const long int &v2) const; + void edgeWeightNumbersVisibilitySet (const bool &toggle); - void setArcWeight (const long int &v1, const long int &v2, const float &w); - void setInitEdgeColor(const QString &); + void edgeLabelSet(const long int &v1, const long int &v2, const QString &label); + QString edgeLabel (const long int &v1, const long int &v2) const; + void edgeLabelsVisibilitySet (const bool &toggle); - void setEdgeColor(const long int &v1, const long int &v2, const QString &color); + void edgeColorInit(const QString &); + void edgeColorSet(const long int &v1, const long int &v2, const QString &color); QString edgeColor (const long int &v1, const long int &v2); - bool setAllEdgesColor(const QString &color); + bool edgeColorAllSet(const QString &color, const int &threshold=RAND_MAX); + //GRAPH methods float density(); + bool isWeighted(); - bool symmetricEdge(int v1, int v2); bool isSymmetric(); void symmetrize(); - void createAdjacencyMatrix(const bool dropIsolates=false, + void undirectedSet(const bool &toggle); + bool isUndirected(); + + void adjacencyMatrixCreate(const bool dropIsolates=false, const bool considerWeights=true, const bool inverseWeights=false, const bool symmetrize=false ); - bool invertAdjacencyMatrix(const QString &method); + bool adjacencyMatrixInvert(const QString &method); /* PRINT OUT TO FILES*/ void writeDataSetToFile(const QString dir, const QString ); void writeAdjacencyMatrixTo(QTextStream& os); - void writeAdjacencyMatrix(const QString, const char*); + void writeAdjacencyMatrix(const QString fileName, QString netName); - void writeInvertAdjacencyMatrix(const QString &filename, - const QString &, - const QString &); - void writeDistanceMatrix(const QString fn, const char*, + void writeAdjacencyMatrixInvert(const QString &filename, + const QString &netName, + const QString &method); + void writeDistanceMatrix(const QString fn, QString netName, const bool considerWeights, const bool inverseWeights, const bool dropIsolates); - void writeNumberOfGeodesicsMatrix(const QString fn, const char*, + void writeNumberOfGeodesicsMatrix(const QString fn, const QString &, const bool considerWeights, const bool inverseWeights); void writeEccentricity(const QString, const bool considerWeights, @@ -388,11 +454,11 @@ public slots: int distance(const int, const int, const bool considerWeights, const bool inverseWeights); int diameter(const bool considerWeights, const bool inverseWeights); - float averageGraphDistance(const bool considerWeights, + float distanceGraphAverage(const bool considerWeights, const bool inverseWeights, const bool dropIsolates); int connectedness(); - void createDistanceMatrix(const bool centralities=false, + void distanceMatrixCreate(const bool centralities=false, const bool considerWeights=false, const bool inverseWeights=true, const bool dropIsolates=false); @@ -410,36 +476,39 @@ public slots: const bool dropIsolates=false); /* REACHABILTY AND WALKS */ - int numberOfWalks(int v1, int v2,int length); - void createNumberOfWalksMatrix(int length); - void writeTotalNumberOfWalksMatrix(QString fn, QString netName, int length); - void writeNumberOfWalksMatrix(QString fn, QString netName, int length); + int walksBetween(int v1, int v2,int length); + void walksMatrixCreate(const int length, + const bool updateProgress=false); + void writeWalksTotalMatrix(QString fn, QString netName, int length); + void writeWalksOfLengthMatrix(QString fn, QString netName, int length); int reachable(int v1, int v2) ; - QList influenceRange(int v1); - QList influenceDomain(int v2); + QList vertexinfluenceRange(int v1); + QList vertexinfluenceDomain(int v2); void reachabilityMatrix(const bool considerWeights=false, const bool inverseWeights=false, - const bool dropIsolates=false); + const bool dropIsolates=false, + const bool updateProgress=false); void writeReachabilityMatrix(QString fn, QString netName, const bool dropIsolates=false); float numberOfTriples(int v1); - float countCliquesWith(int source, int size=0); - bool addClique (const QList &list); - float countCliquesOfSize(int size ); - float localClusteringCoefficient(const long int &v1); - float clusteringCoefficient (); + + bool cliqueAdd (const QList &list); + float cliquesContaining(int source, int size=0); + float cliquesOfSize(int size ); + float clusteringCoefficientLocal(const long int &v1); + float clusteringCoefficient (const bool updateProgress=false); bool triadCensus(); - void examine_MAN_label(int, int, int, Vertex*, Vertex*, Vertex* ); + void triadType_examine_MAN_label(int, int, int, Vertex*, Vertex*, Vertex* ); // void eccentr_JordanCenter(); // TODO /* LAYOUTS */ - void layoutRandom( double maxWidth, double maxHeight ); + void layoutRandom(); void layoutCircularRandom(double x0, double y0, double maxRadius); @@ -458,35 +527,34 @@ public slots: const bool inverseWeights, const bool dropIsolates); - void layoutForceDirectedSpringEmbedder(bool &dynamicMovement); + void layoutForceDirectedSpringEmbedder(const int maxIterations); - void layoutForceDirectedFruchtermanReingold(bool dynamicMovement); + void layoutForceDirectedFruchtermanReingold(const int maxIterations); + void layoutForceDirectedKamadaKawai(const int maxIterations); /* CRAWLER */ - void terminateCrawlerThreads (QString reason); + void webCrawlTerminateThreads (QString reason); /**RANDOM NETWORKS*/ + void randomizeThings(); - - - void makeThingsLookRandom(); - - - void createRandomNetErdos ( const int &vert, + void randomNetErdosCreate ( const int &vert, const QString &model, const int &edges, const float &eprob, const QString &mode, const bool &diag); - void createRandomNetRingLattice - (int, int, double, double, double); + void randomNetRingLatticeCreate ( const int &vert, const int °ree, + const double &x0, const double &y0, + const double &radius, + const bool updateProgress=false); - void createSameDegreeRandomNetwork - (int, int); + void randomNetSameDegreeCreate (const int &, + const int &); - void createRandomNetScaleFree (const int &n, + void randomNetScaleFreeCreate (const int &n, const int &power, const int &m0, const int &m, @@ -496,14 +564,13 @@ public slots: const double &y0, const double &radius); - - void createRandomNetSmallWorld - (int, int, double, double, double, double); + void randomNetSmallWorldCreate(const int &vert, const int °ree, + const double &beta, const QString &mode, + const double &x0, + const double &y0, const double &radius); int factorial (int); - int relations(); - void addRelationFromGraph(QString relationName); /** index stores the real position of each vertex inside m_graph. * It starts at zero (0). @@ -538,17 +605,19 @@ public slots: WebCrawler_Spider *wc_spider; /** private member functions */ - - void addVertex ( - int v1, int val, int size, QString color, - QString numColor, int numSize, - QString label, QString labelColor, int labelSize, - QPointF p, QString shape - ); - - void addEdge (int v1, int v2, float w, QString color, int reciprocal); - - /** methods used by createDistanceMatrix() */ + void vertexAdd ( const int &v1, const int &val, const int &size, + const QString &color, const QString &numColor, + const int &numSize, const QString &label, + const QString &labelColor, const int &labelSize, + const QPointF &p, const QString &shape ); + + void edgeAdd (const int &v1, const int &v2, const float &weight, + const int &type, + const QString &label, + const QString &color + ); + + /** methods used by distanceMatrixCreate() */ void BFS(const int s, const bool computeCentralities, const bool dropIsolates); void dijkstra(const int s,const bool computeCentralities, @@ -579,16 +648,17 @@ public slots: Matrix XM, XSM, XRM; stack Stack; - /** used in resolveClasses and createDistanceMatrix() */ + /** used in resolveClasses and distanceMatrixCreate() */ H_StrToInt discreteDPs, discreteDCs, discreteCCs, discreteBCs, discreteSCs; H_StrToInt discreteIRCCs, discreteECs, discreteEccentricities; H_StrToInt discretePCs, discreteICs, discretePRPs, discretePPs; - bool calculatedDP, calculatedDC, calculatedCentralities, dynamicMovement; + bool calculatedDP, calculatedDC, calculatedCentralities; bool calculatedPP, calculatedIRCC, calculatedIC, calculatedPRP; bool calculatedTriad; int m_precision, m_curRelation; + float edgeWeightTemp; float meanDC, varianceDC; float meanCC, varianceCC; float meanIRCC, varianceIRCC; @@ -632,17 +702,19 @@ public slots: long int m_totalVertices, graphDiameter, initVertexSize; int initVertexLabelSize, initVertexNumberSize; + int initVertexNumberDistance, initVertexLabelDistance; int isolatedVertices; float averGraphDistance, nonZeroDistancesCounter; int outboundEdgesVert, inboundEdgesVert, reciprocalEdgesVert; - int timerId, layoutType, canvasWidth, canvasHeight; - - bool order, initShowLabels, initNumbersInsideNodes; + int timerId, canvasWidth, canvasHeight; + bool order, initVertexLabelsVisibility,initVertexNumbersVisibility; + bool initNumbersInsideNodes; bool adjacencyMatrixCreated, symmetricAdjacencyMatrix, graphModified, distanceMatrixCreated; bool reachabilityMatrixCreated; bool m_undirected; + bool initEdgeWeightNumbers, initEdgeLabels; QString VERSION, networkName, initEdgeColor, initVertexColor, initVertexNumberColor, initVertexLabelColor, initVertexShape; diff --git a/src/graphicswidget.cpp b/src/graphicswidget.cpp index dec45483..1b5e1436 100755 --- a/src/graphicswidget.cpp +++ b/src/graphicswidget.cpp @@ -5,7 +5,7 @@ graphicswidget.cpp description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -40,6 +40,7 @@ #include "nodelabel.h" #include "guide.h" #include "edgeweight.h" +#include "edgelabel.h" /** Constructor method. Called when a GraphicsWidget object is created in MW @@ -47,12 +48,10 @@ GraphicsWidget::GraphicsWidget( QGraphicsScene *sc, MainWindow* par) : QGraphicsView ( sc,par) { setScene(sc); secondDoubleClick=false; - dynamicMovement=false; + transformationActive = false; moving=0; - timerId=0; - layoutType=0; m_nodeLabel=""; - zoomIndex=3; + m_zoomIndex=250; m_currentScaleFactor = 1; m_currentRotationAngle = 0; markedNodeExist=false; //used in findNode() @@ -78,7 +77,7 @@ void GraphicsWidget::paintEvent ( QPaintEvent * event ){ Clears the scene */ void GraphicsWidget::clear() { - qDebug() << " clear GW"; + qDebug() << "GW::clear()"; nodeHash.clear(); edgesHash.clear(); scene()->clear(); @@ -89,69 +88,58 @@ void GraphicsWidget::clear() { } /** - * @brief GraphicsWidget::changeRelation + * @brief GraphicsWidget::relationSet * Called from Graph::relationChanged(int) signal * @param relation */ -void GraphicsWidget::changeRelation(int relation) { - qDebug() << "GraphicsWidget::changeRelation() to " << relation; +void GraphicsWidget::relationSet(int relation) { + qDebug() << "GraphicsWidget::relationSet() to " << relation; m_curRelation = relation; } -/** - Adds a new node onto the scene - Called from Graph::createVertex method when: - we load files or - the user presses "Add Node" button or - the user double clicks (mouseDoubleClickEvent() calls Graph::createVertex -*/ -void GraphicsWidget::drawNode( - int num, int size, QString nodeColor, - QString numberColor, int numberSize, - QString nodeLabel, QString labelColor, int labelSize, - QPointF p, - QString shape, - bool showLabels, bool numberInsideNode, bool showNumbers - ) { - qDebug()<< "GW: drawNode(): drawing new node at: " - << p.x() << ", "<< p.y() ; - - if (numberInsideNode) - size = size +3; - +/** + * @brief GraphicsWidget::drawNode + * Adds a new node onto the scene + * Called from Graph::vertexCreate method primarily when we load files + * It is also called in the end when the user presses "Add Node" button or + * the user double clicks (mouseDoubleClickEvent() calls Graph::vertexCreate) + * @param num + * @param nodeSize + * @param nodeColor + * @param numberColor + * @param numberSize + * @param nodeLabel + * @param labelColor + * @param labelSize + * @param p + * @param nodeShape + * @param showLabels + * @param numberInsideNode + * @param showNumbers + */ +void GraphicsWidget::drawNode( const int &num, const int &nodeSize, + const QString &nodeShape, const QString &nodeColor, + const bool &showNumbers,const bool &numberInsideNode, + const QString &numberColor, const int &numberSize, + const bool &showLabels, const QString &nodeLabel, + const QString &labelColor, const int &labelSize, + const QPointF &p + ) { + qDebug()<< "GW: drawNode(): drawing new node " << num + << " at: " << p.x() << ", "<< p.y() ; + + //Draw node Node *jim= new Node ( - this, num, size, nodeColor, shape, - numberInsideNode, m_labelDistance, m_numberDistance, + this, num, nodeSize, nodeColor, nodeShape, + showNumbers, numberInsideNode, numberColor, numberSize, m_numberDistance, + showLabels, nodeLabel, labelColor, labelSize, m_labelDistance, p ); - //Drawing node label - label will be moved by the node movement (see last code line in this method) - NodeLabel *labelJim = new NodeLabel (jim, labelSize, nodeLabel ); - labelJim -> setDefaultTextColor (labelColor); - labelJim -> setTextInteractionFlags(Qt::TextEditorInteraction); - - if (showLabels) { - //qDebug()<< "GW: drawNode: display label " << nodeLabel.toUtf8() << " for node " << num; - } - else { - //qDebug()<<"GW: drawNode: hiding label for node " << num; - labelJim->hide(); - } - - // drawing node number - label will be moved by the node movement (see last code line in this method) - if (numberInsideNode) - numberSize = size-2; - - NodeNumber *numberJim = new NodeNumber ( jim, numberSize, QString::number(num)); - numberJim -> setDefaultTextColor (numberColor); - - if (!showNumbers){ - numberJim->hide(); - } - nodeHash.insert(num, jim);//add new node to a container to ease finding, edge creation etc - jim -> setPos( p.x(), p.y()); //finally, move the node where it belongs! + //add new node to a container to ease finding, edge creation etc + nodeHash.insert(num, jim); } @@ -159,77 +147,62 @@ void GraphicsWidget::drawNode( -/** Draws an edge from source to target Node. - This is used when we do not have references to nodes - only nodeNumbers: - a) when we load a network file (check = FALSE) + +/** + * @brief GraphicsWidget::drawEdge + * Draws an edge from source to target Node. + * Used when we do not have references to nodes but only nodeNumbers: + a) when we load a network file b) when the user clicks on the AddLink button on the MW. -*/ -void GraphicsWidget::drawEdge(int i, int j, float weight, bool reciprocal, bool drawArrows, QString color, bool bezier){ + * @param source + * @param target + * @param weight + * @param reciprocal + * @param drawArrows + * @param color + * @param bezier + */ +void GraphicsWidget::drawEdge(const int &source, const int &target, + const float &weight, + const QString &label, + const QString &color, + const int &type, + const bool &drawArrows, + const bool &bezier, + const bool &weightNumbers){ + + edgeName = QString::number(m_curRelation) + QString(":") + + QString::number(source) + QString(">")+ QString::number(target); + qDebug()<<"GW::drawEdge() - "<< edgeName + << " weight "<")+ QString::number(j); - qDebug()<<"GW: drawEdge "<< edgeName << "weight "<nodeNumber()<< " to node " - // << nodeHash.value(j)->nodeNumber() << " weight " - // << weight << " nodesize " - // << m_nodeSize << " edgecolor "<< color ; - Edge *edge=new Edge (this, nodeHash.value(i), nodeHash.value(j), - Qt::SolidLine, - weight, - m_nodeSize, color, reciprocal, drawArrows, bezier); - edge -> setZValue(253); //Edges have lower z than nodes. Nodes always appear above edges. - // Keep it here so that it doesnt interfere with dashed lines. - edge->setBoundingRegionGranularity(0.05); // Slows down the universe...Keep it 0.05... - //edge->setCacheMode (QGraphicsItem::DeviceCoordinateCache); //Also slows down the universe... - - // qDebug()<<"GW: drawEdge() - adding new edge between "<x() + (nodeHash.value(j))->x() ) / 2.0; - double y = ( (nodeHash.value(i))->y() + (nodeHash.value(j))->y() ) / 2.0; - // qDebug()<< "GW: drawEdge(): edge weight will be at " << x << ", " << y; - EdgeWeight *edgeWeight = new EdgeWeight (edge, 7, QString::number(weight) ); - edgeWeight-> setPos(x,y); - edgeWeight-> setDefaultTextColor (color); - edgeWeight-> hide(); - - // qDebug()<< "Scene items now: "<< scene()->items().size() << " - GW items now: "<< items().size(); -} + Edge *edge=new Edge (this, + nodeHash.value(source), nodeHash.value(target), + weight, label, color, + Qt::SolidLine, + type, + drawArrows, + (source==target) ? true: bezier, + weightNumbers); + edgesHash.insert(edgeName, edge); + if (type == EDGE_DIRECTED_OPPOSITE_EXISTS ) { + edgeName = QString::number(m_curRelation) + QString(":") + + QString::number(target) + QString(">")+ QString::number(source); + // qDebug("GW: making existing edge between %i and %i reciprocal. Name: "+edgeName.toUtf8(), source, target ); + edgesHash.value(edgeName)->setDirectedWithOpposite(); -/** - Called from Graph to make an existing arc symmetric (reciprocal) -*/ -void GraphicsWidget::drawEdgeReciprocal(int source, int target){ - qDebug("GW: drawEdgeReciprocal ()"); - QString edgeName = QString::number(m_curRelation) + QString(":") + - QString::number(source) + QString(">")+ QString::number(target); - // qDebug("GW: making existing edge between %i and %i reciprocal. Name: "+edgeName.toUtf8(), source, target ); - edgesHash.value(edgeName)->makeReciprocal(); + } + // qDebug()<< "Scene items now: "<< scene()->items().size() << " - GW items now: "<< items().size(); } -/** - Called from Graph to unmake an existing symmetric (reciprocal) edge to one-directed only. -*/ -void GraphicsWidget::unmakeEdgeReciprocal(int source, int target){ - qDebug("GW: unmakeEdgeReciprocal ()"); - QString edgeName = QString::number(m_curRelation) + QString(":") + - QString::number(source) + QString(">")+ QString::number(target); - // qDebug("GW: removing edge between %i and %i. Name: "+edgeName.toUtf8(), source, target ); - edgesHash.value(edgeName)->unmakeReciprocal(); -} - /** @@ -306,17 +279,6 @@ void GraphicsWidget::edgeClicked(Edge *edge){ -/** - On the event of a right-click on a node, the node calls this function - to emit a signal to MW to open a context menu at the mouse position. - Node is already passed with selectedNode(Node *) signal - The position of the menu is determined by QMouse:pos()... -*/ -void GraphicsWidget::openNodeContextMenu(){ - qDebug("GW: emitting openNodeMenu()"); - emit openNodeMenu(); -} - /** On the event of a right-click on an edge, the edge calls this function @@ -332,69 +294,95 @@ void GraphicsWidget::openEdgeContextMenu(){ -/** - Called from each node when they move. - Updates +/** + * @brief GraphicsWidget::nodeMoved + * Called from each node when they move. + * Updates: - node coordinates in activeGraph (via updateNodeCoords() signal) - -*/ -void GraphicsWidget::nodeMoved(int number, int x, int y){ + * @param number + * @param x + * @param y + */ +void GraphicsWidget::nodeMoved(const int &number, const int &x, const int &y){ //qDebug ("GW: nodeMoved() for %i with %i, %i. Emitting updateNodeCoords() signal", number, x,y); emit updateNodeCoords(number, x, y); } -/** - Called from activeGraph to update node coordinates - on the canvas -*/ -void GraphicsWidget::moveNode(int number, qreal x, qreal y){ - qDebug() << " GW: moveNode() " << number << ": " << x << y; - nodeHash.value(number)->setPos(x,y); +/** + * @brief GraphicsWidget::moveNode + * Called from activeGraph to update node coordinates on the canvas + * @param num + * @param x + * @param y + */ +void GraphicsWidget::moveNode(const int &num, const qreal &x, const qreal &y){ + qDebug() << " GW: moveNode() " << num << ": " << x << y; + nodeHash.value(num)->setPos(x,y); // qDebug() << "GW: moveNode() node reports x, y as " // << nodeHash.value(number)->x() << nodeHash.value(number)->x(); } + /** - Called from Graph signal eraseNode(int) -*/ -void GraphicsWidget::eraseNode(long int doomedJim){ - qDebug() << "GW: Deleting node "<< doomedJim; - QList list=scene()->items(); - qDebug("GW: Scene items= %i - View items : %i",scene()->items().size(), items().size()); - for (QList::iterator it=list.begin(); it!=list.end(); it++) { - if ( (*it)->type()==TypeNode) { - Node *jim=(Node*) (*it); - if ( jim->nodeNumber()==doomedJim) { - qDebug() << "GW: found doomedJim " << jim->nodeNumber() << " Demanding node->die() :)" ; - delete *it; - break; - } - } + * @brief GraphicsWidget::eraseNode + * Called from Graph signal eraseNode(int) + * @param number + */ +void GraphicsWidget::eraseNode(const long int &number){ + qDebug() << "GW::eraseNode() - node " << number + << " scene items: " << scene()->items().size() + << " view items: " << items().size() + << " nodeHash items: "<< nodeHash.count(); + + if ( nodeHash.contains(number) ) { + qDebug() << "GW::eraseNode() - found number " + << number<< " Deleting :)" ; + delete nodeHash.value(number); + nodeHash.remove(number); } - qDebug("GW: Scene items now= %i - View items now= %i ", scene()->items().size(), items().size() ); + + qDebug() << "GW::eraseNode() - node erased! " + << " scene items now: " << scene()->items().size() + << " view items: " << items().size() + << " nodeHash items: "<< nodeHash.count() + << " edgesHash items: "<< edgesHash.count() ; } + /** - Called from MainWindow when erasing edges using vertex numbers -*/ -void GraphicsWidget::eraseEdge(int sourceNode, int targetNode){ - qDebug("GW: Scene items= %i - View items : %i",scene()->items().size(), items().size()); - QList list=scene()->items(); - for (QList::iterator it=list.begin(); it!= list.end() ; it++){ - if ( (*it)->type()==TypeEdge ) { - Edge *edge=(Edge*) (*it); - if ( edge->sourceNodeNumber()==sourceNode && edge->targetNodeNumber()==targetNode ) { - removeItem(edge); - break; - } - } + * @brief GraphicsWidget::eraseEdge + * Called from MW/Graph when erasing edges using vertex numbers + * Also called when transforming directed edges to undirected. + * @param sourceNode + * @param targetNode + */ +void GraphicsWidget::eraseEdge(const long int &source, const long int &target){ + qDebug() << "GW::eraseEdge(): " << source << " -> " << target + << " scene items: " << scene()->items().size() + << " view items: " << items().size() + << " edgesHash.count: " << edgesHash.count(); + + + edgeName = QString::number(m_curRelation) + QString(":") + + QString::number( source ) + + QString(">") + + QString::number( target ); + + if ( edgesHash.contains(edgeName) ) { + delete edgesHash.value(edgeName); } - qDebug("GW: Scene items now= %i - View items now= %i ", scene()->items().size(), items().size() ); + + + qDebug() << "GW::eraseEdge() - deleted " + << " scene items: " << scene()->items().size() + << " view items: " << items().size() + << " edgesHash.count: " << edgesHash.count(); + } @@ -410,12 +398,13 @@ void GraphicsWidget::eraseEdge(int sourceNode, int targetNode){ */ void GraphicsWidget::removeItem( Node *node){ long int i=node->nodeNumber(); - foreach ( Node *candidate, nodeHash) { - if ( candidate->nodeNumber() == i ) - nodeHash.remove( i ); - } + qDebug() << "GW::removeItem(node) - number: " << i; + + scene()->removeItem(node); node->deleteLater (); - qDebug() << "GW items now: " << items().size(); + qDebug() << "GW::removeItem(node) - node erased! " + << " scene items now: " << scene()->items().size() + << " view items: " << items().size(); } @@ -423,21 +412,72 @@ void GraphicsWidget::removeItem( Node *node){ /** Called from Node::die() to remove Edge edge ... */ void GraphicsWidget::removeItem( Edge * edge){ - //edge->remove(); - delete (edge); + qDebug() << "GW::removeItem(edge)" ; + edgeName = QString::number(m_curRelation) + QString(":") + + QString::number( edge->sourceNodeNumber() ) + + QString(">") + + QString::number( edge->targetNodeNumber() ); + edgesHash.remove(edgeName); + scene()->removeItem(edge); + edge->deleteLater(); + qDebug() << "GW::removeItem(edge) - edge erased! " + << " scene items now: " << scene()->items().size() + << " view items: " << items().size(); +} + + +/** + * @brief GraphicsWidget::removeItem + * @param edgeWeight + */ +void GraphicsWidget::removeItem( EdgeWeight *edgeWeight){ + qDebug() << "GW::removeItem(edgeWeight) - of edge" + << "GW items now: " << items().size(); + scene()->removeItem(edgeWeight); + edgeWeight->deleteLater(); + qDebug() << "GW::removeItem(edgeWeight) - edgeWeight erased! " + << " scene items now: " << scene()->items().size() + << " view items: " << items().size(); +} + +/** + * @brief GraphicsWidget::removeItem + * @param edgeLabel + */ +void GraphicsWidget::removeItem( EdgeLabel *edgeLabel){ + qDebug() << "GW::removeItem(edgeLabel) - of edge" + << "GW items now: " << items().size(); + scene()->removeItem(edgeLabel); + edgeLabel->deleteLater(); + qDebug() << "GW::removeItem(edgeLabel) - edgeLabel erased! " + << " scene items now: " << scene()->items().size() + << " view items: " << items().size(); } void GraphicsWidget::removeItem( NodeLabel *nodeLabel){ - qDebug() << "GW items now: " << items().size(); - delete (nodeLabel); - qDebug() << "GW items now: " << items().size(); + qDebug() << "GW::removeItem(label) - of node " << nodeLabel->node()->nodeNumber() + << "GW items now: " << items().size(); + scene()->removeItem(nodeLabel); + nodeLabel->deleteLater(); + qDebug() << "GW::removeItem(label) - label erased! " + << " scene items now: " << scene()->items().size() + << " view items: " << items().size(); + + } void GraphicsWidget::removeItem( NodeNumber *nodeNumber){ - delete (nodeNumber); + qDebug() << "GW::removeItem(number) - of node " << nodeNumber->node()->nodeNumber() + << "GW items now: " << items().size(); + scene()->removeItem(nodeNumber); + nodeNumber->deleteLater(); + qDebug() << "GW::removeItem(number) - number erased! " + << " scene items now: " << scene()->items().size() + << " view items: " << items().size(); + } @@ -461,95 +501,223 @@ void GraphicsWidget::setInitNodeColor(QString color){ Called from MW on startup and when user changes it. */ void GraphicsWidget::setInitLinkColor(QString color){ - qDebug("GW setting initLinkColor"); + qDebug()<< "GW::setInitLinkColor"; m_linkColor=color; } -/** - Sets the color of an node. - Called from MW when the user changes the color of a node (right-clicking). -*/ -bool GraphicsWidget::setNodeColor(long int nodeNumber, QString color){ - qDebug() << "GraphicsWidget::setNodeColor() : " << color; +/** + * @brief GraphicsWidget::setNodeColor + * Sets the color of an node. + * Called from MW when the user changes the color of a node (right-clicking). + * @param nodeNumber + * @param color + * @return + */ +bool GraphicsWidget::setNodeColor(const long int &nodeNumber, + const QString &color){ + qDebug() << "GW::setNodeColor() : " << color; nodeHash.value(nodeNumber) -> setColor(color); return true; - } /** - Sets the label of an node. - Called from MW when the user changes it + Sets the shape of an node. + Called from MW when the user changes the shape of a node */ +bool GraphicsWidget::setNodeShape(const long &nodeNumber, const QString &shape){ + qDebug() << "GW::setNodeShape() : " << shape; + nodeHash.value(nodeNumber) -> setShape(shape); + return true; + +} + + + + + +void GraphicsWidget::setNodeNumberVisibility(const bool &toggle){ + qDebug()<< "GW::setNodeNumberVisibility()" << toggle; + foreach ( Node *m_node, nodeHash) { + m_node->setNumberVisibility(toggle); + } +} + +void GraphicsWidget::setNodeLabelsVisibility (const bool &toggle){ + qDebug()<< "GW::setNodeLabelsVisibility()" << toggle; + foreach ( Node *m_node, nodeHash) { + m_node->setLabelVisibility(toggle); + } +} + + +/** + * @brief GraphicsWidget::setNodeLabel + * Sets the label of an node. Called from MW. + * @param nodeNumber + * @param label + * @return + */ bool GraphicsWidget::setNodeLabel(long int nodeNumber, QString label){ - qDebug() << "GraphicsWidget::setNodeLabel() : " << label; + qDebug() << "GW::setNodeLabel() : " << label; nodeHash.value(nodeNumber) -> setLabelText (label); return true; } -/** - Makes node label appear inside node. - Called from MW on user request. -*/ + +/** + * @brief GraphicsWidget::setNumbersInsideNodes + * Toggles node numbers displayed inside or out of nodes + * Called from MW + * @param numIn + */ void GraphicsWidget::setNumbersInsideNodes(bool numIn){ - qDebug("GW setting initNumberDistance"); + qDebug()<< "GW::setNumbersInsideNodes" << numIn; foreach ( Node *m_node, nodeHash) { m_node->setNumberInside(numIn); - if (numIn) - this->setInitNodeSize(m_nodeSize+2); - else - this->setInitNodeSize(m_nodeSize-2); - } } -/** - Changes/Sets the color of an edge. - Called from MW when the user changes the color of an edge (right-clicking). -*/ -void GraphicsWidget::setEdgeColor(long int source, long int target, QString color){ + + + +/** + * @brief GraphicsWidget::setEdgeLabel + * Sets the label of an edge. + * Called from MW when the user changes the label of an edge (right-clicking). + * @param source + * @param target + * @param label + */ +void GraphicsWidget::setEdgeLabel(const long int &source, + const long int &target, + const QString &label){ + + QString edgeName = QString::number(m_curRelation) + QString(":") + + QString::number( source ) + QString(">")+ QString::number( target ); + + qDebug()<<"GW::setEdgeLabel() -" << edgeName << " new label " << label; + if ( edgesHash.contains (edgeName) ) { + edgesHash.value(edgeName) -> setLabel(label); + } + + +} + +/** + * @brief GraphicsWidget::setEdgeColor + * Sets the color of an edge. + * Called from MW when the user changes the color of an edge (right-clicking). + * Also called from Graph when all edge colors need to be changed. + * @param source + * @param target + * @param color + */ +void GraphicsWidget::setEdgeColor(const long int &source, + const long int &target, + const QString &color){ QString edgeName = QString::number(m_curRelation) + QString(":") + QString::number( source ) + QString(">")+ QString::number( target ); - qDebug()<<"GW::setEdgeColor() -" << edgeName << " to " << color;; + qDebug()<<"GW::setEdgeColor() -" << edgeName << " new color " << color; + if ( edgesHash.contains (edgeName) ) { + edgesHash.value(edgeName) -> setColor(color); + } - // if ( edgesHash.contains (edgeName) ) { // VERY SLOW - edgesHash.value(edgeName) -> setColor(color); } + + +/** + * @brief GraphicsWidget::setEdgeUndirected + * Makes an edge undirected + * @param source + * @param target + * @param weight + * @return + */ +bool GraphicsWidget::setEdgeUndirected(const long int &source, + const long int &target, + const float &weight){ + qDebug() << "GW::setEdgeUndirected() : " << source << "->" << target + << " = " << weight; + + QString edgeName = QString::number(m_curRelation) + QString(":") + + QString::number( source ) + QString(">")+ QString::number( target ); + + qDebug()<<"GW::setEdgeUndirected() - checking edgesHash for:" << edgeName ; + if ( edgesHash.contains (edgeName) ) { + qDebug()<<"GW::setEdgeUndirected() - edge exists in edgesHash. " + << " Transforming it to undirected"; + edgesHash.value(edgeName) -> setUndirected(); + + qDebug()<<"GW::setEdgeUndirected() - removing opposite edge " + << target << " -> " << source ; + eraseEdge(target, source); + + return true; + } + return false; + +} + + + /** Changes/Sets the weight of an edge. Called from MW when the user changes the weight of an edge (right-clicking). */ -bool GraphicsWidget::setEdgeWeight(int source, int target, float weight){ - QList list=scene()->items(); - for (QList::iterator it=list.begin(); it!= list.end() ; it++){ - if ( (*it)->type()==TypeEdge) { - Edge *edge=(Edge*) (*it); - if ( edge->sourceNodeNumber()==source && edge->targetNodeNumber()==target ) { - edge->setWeight(weight); - edge->update(); - return true; - } - } +bool GraphicsWidget::setEdgeWeight(const long int &source, + const long int &target, + const float &weight){ + qDebug() << "GW::setEdgeWeight() : " << source << "->" << target + << " = " << weight; + + QString edgeName = QString::number(m_curRelation) + QString(":") + + QString::number( source ) + QString(">")+ QString::number( target ); + + qDebug()<<"GW::setEdgeWeight() -" << edgeName << " new weight " << weight; + if ( edgesHash.contains (edgeName) ) { + edgesHash.value(edgeName) -> setWeight(weight); + return true; } return false; + } +void GraphicsWidget::setEdgeWeightNumbersVisibility (const bool &toggle){ + qDebug()<< "GW::setEdgeWeightNumbersVisibility()" << toggle; + foreach ( Edge *m_edge, edgesHash) { + m_edge->setWeightNumberVisibility(toggle); + } +} + + + + +void GraphicsWidget::setEdgeLabelsVisibility (const bool &toggle){ + qDebug()<< "GW::setEdgeLabelsVisibility()" << toggle + << "edgesHash.count: " << edgesHash.count(); + foreach ( Edge *m_edge, edgesHash) { + m_edge->setLabelVisibility(toggle); + } +} + + /** Sets initial node size from MW. It is Called from MW on startup and when user changes it. @@ -582,6 +750,16 @@ void GraphicsWidget::setInitLabelDistance(int labelDistance){ } +/** + * @brief GraphicsWidget::setInitZoomIndex + * Passes initial zoom setting + * Called from MW on startup + */ +void GraphicsWidget::setInitZoomIndex(int zoomIndex) { + m_zoomIndex = zoomIndex; +} + + @@ -628,7 +806,7 @@ void GraphicsWidget::setNodeVisibility(long int number, bool toggle){ * @param size * @return */ -bool GraphicsWidget::setNodeSize(long int number, int size ){ +bool GraphicsWidget::setNodeSize(const long int &number, const int &size ){ qDebug () << " GraphicsWidget::setNodeSize() node: "<< number << " new size "<< size; if ( nodeHash.contains (number) ) { @@ -655,7 +833,7 @@ bool GraphicsWidget::setNodeSize(long int number, int size ){ * @param size * @return */ -void GraphicsWidget::setAllNodeSize(int size ){ +void GraphicsWidget::setAllNodeSize(const int &size ){ qDebug() << "GW: setAllNodeSize() "; foreach ( Node *m_node, nodeHash ) { if (size>0){ @@ -670,6 +848,127 @@ void GraphicsWidget::setAllNodeSize(int size ){ } + +/** + * @brief GraphicsWidget::setNodeNumberSize + * @param number + * @param size + */ +bool GraphicsWidget::setNodeNumberSize(const long int &number, const int &size){ + qDebug () << " GraphicsWidget::setNodeNumberSize() node number: "<< number + << " new number size "<< size; + if ( nodeHash.contains (number) ) { + if (size>0){ + qDebug() << "GW: setNodeNumberSize(): for "<< number << " to " << size ; + nodeHash.value(number) ->setNumberSize(size) ; + return true; + + } + else { + qDebug() << "GW: setNodeNumberSize(): for "<< number + << " to initial size" << m_nodeSize; + nodeHash.value(number) ->setNumberSize(size); + return true; + + } + } + qDebug() << "GW: setNodeSize(): cannot find node " << number; + return false; +} + + + +/** + * @brief GraphicsWidget::setNodeNumberDistance + * @param number + * @param distance + */ +bool GraphicsWidget::setNodeNumberDistance( const long int &number, const int &distance ){ + qDebug () << " GraphicsWidget::setNodeNumberDistance() node number: "<< number + << " new number distance "<< distance; + if ( nodeHash.contains (number) ) { + if (distance>0){ + qDebug() << "GW: setNodeNumberDistance(): for "<< number + << " to " << distance ; + nodeHash.value(number) ->setNumberDistance(distance) ; + return true; + + } + else { + qDebug() << "GW: setNodeNumberSize(): for "<< number + << " to initial size" << distance; + nodeHash.value(number) ->setNumberDistance(distance); + return true; + + } + } + qDebug() << "GW: setNodeSize(): cannot find node " << number; + return false; +} + + + +/** + * @brief GraphicsWidget::setNodeLabelSize + * @param number + * @param size + */ +bool GraphicsWidget::setNodeLabelSize(const long int &number, const int &size){ + qDebug () << " GraphicsWidget::setNodeLabelSize() node number: "<< number + << " new Label size "<< size; + if ( nodeHash.contains (number) ) { + if (size>0){ + qDebug() << "GW: setNodeLabelSize(): for "<< number << " to " << size ; + nodeHash.value(number) ->setLabelSize(size); + return true; + + } + else { + qDebug() << "GW: setNodeLabelSize(): for "<< number + << " to initial size" << m_nodeSize; + nodeHash.value(number) ->setLabelSize(size); + return true; + + } + } + qDebug() << "GW: setNodeSize(): cannot find node " << number; + return false; +} + + + + + +/** + * @brief GraphicsWidget::setNodeLabelDistance + * @param number + * @param distance + */ +bool GraphicsWidget::setNodeLabelDistance( const long int &number, const int &distance ){ + qDebug () << " GraphicsWidget::setNodeLabelDistance() node number: "<< number + << " new label distance "<< distance; + if ( nodeHash.contains (number) ) { + if (distance>0){ + qDebug() << "GW: setNodeLabelDistance(): for "<< number + << " to " << distance ; + nodeHash.value(number) ->setLabelDistance(distance) ; + return true; + + } + else { + qDebug() << "GW: setNodeLabelDistance(): for "<< number + << " to initial size" << distance; + nodeHash.value(number) ->setLabelDistance(distance); + return true; + + } + } + qDebug() << "GW: setNodeSize(): cannot find node " << number; + return false; +} + + + /* * Used by findNode. * Returns, if found, the node with label or number 'text' @@ -695,7 +994,7 @@ Node* GraphicsWidget::hasNode( QString text ){ /** Marks (by double-sizing and highlighting) or unmarks a node, given its number or label. - Called by MW:slotFindNode() + Called by MW:slotEditNodeFind() */ bool GraphicsWidget::setMarkedNode(QString nodeText){ qDebug ("GW: setMarkedNode()"); @@ -735,15 +1034,17 @@ void GraphicsWidget::setAllItemsVisibility(int type, bool visible){ -void GraphicsWidget::addGuideCircle( int x0, int y0, int radius){ +void GraphicsWidget::addGuideCircle( const double&x0, + const double&y0, + const double&radius){ Guide *circ=new Guide (this, x0, y0, radius); circ->show(); } -void GraphicsWidget::addGuideHLine( int y0){ - Guide *line=new Guide (this, y0, this->width()); +void GraphicsWidget::addGuideHLine(const double &y0){ + Guide *line=new Guide (this, y0, this->width()); line->show(); } @@ -803,28 +1104,34 @@ QList GraphicsWidget::selectedItems(){ /** Starts a new node when the user double-clicks somewhere - Emits userDoubleClicked to MW slot addNodeWithMouse() which + Emits userDoubleClicked to MW::slotEditNodeAddWithMouse() which - displays node info on MW status bar and - - calls Graph::createVertex(), which in turn calls this->drawNode()... + - calls Graph::vertexCreate(), which in turn calls this->drawNode()... Yes, we make a full circle! :) */ void GraphicsWidget::mouseDoubleClickEvent ( QMouseEvent * e ) { - + qDebug() << "GW: mouseDoubleClickEvent()"; if ( QGraphicsItem *item= itemAt(e->pos() ) ) { if (Node *node = qgraphicsitem_cast(item)) { - Q_UNUSED(node); - qDebug() << "GW: mouseDoubleClickEvent() double click on a node detected!" - << " Cant create new one!"; + qDebug() << "GW: mouseDoubleClickEvent() - on a node!" + << " Starting new edge!"; + node->setSelected(true); + nodeClicked(node); + startEdge(node); + QGraphicsView::mouseDoubleClickEvent(e); + return; + } + else if ( (*item).type() == TypeLabel){ + QGraphicsView::mouseDoubleClickEvent(e); return; } } QPointF p = mapToScene(e->pos()); - qDebug()<< "GW::mouseDoubleClickEvent()" - << " double click on empty space. " + qDebug()<< "GW::mouseDoubleClickEvent() - on empty space. " << " Signaling MW to create a new vertex in graph. e->pos() " << e->pos().x() << ","<< e->pos().y() << ", "<< p.x() << "," <items().size() << " GW items: " << items().size(); @@ -838,8 +1145,7 @@ void GraphicsWidget::mousePressEvent( QMouseEvent * e ) { bool ctrlKey = (e->modifiers() == Qt::ControlModifier); - - qDebug() << "GW::mousePressEvent() click at " + qDebug() << "GW::mousePressEvent() - click at " << e->pos().x() << ","<< e->pos().y() << " or "<< p.x() << ","<< p.y() << " selectedItems " << selectedItems().count(); @@ -848,17 +1154,27 @@ void GraphicsWidget::mousePressEvent( QMouseEvent * e ) { if ( QGraphicsItem *item= itemAt(e->pos() ) ) { - qDebug() << "GW::mousePressEvent() click on an item" ; - if (Node *node = qgraphicsitem_cast(item)) { - Q_UNUSED(node); - qDebug() << "GW::mousePressEvent() single click on a node " ; + qDebug() << "GW::mousePressEvent() - single click on a node. " + << "Setting selected and emitting nodeClicked"; + node->setSelected(true); + nodeClicked(node); + if ( e->button()==Qt::RightButton ) { + qDebug() << "GW::mousePressEvent() - Right-click on node. " + << "emitting openNodeMenu() "; + emit openNodeMenu(); + } + if ( e->button()==Qt::MidButton) { + qDebug() << "GW::mousePressEvent() - Middle-click on node. " + << "Calling startEdge() "; + startEdge(node); + } QGraphicsView::mousePressEvent(e); return; } if (Edge *edge= qgraphicsitem_cast(item)) { + qDebug() << "GW::mousePressEvent() - single click on an edge "; Q_UNUSED(edge); - qDebug() << "GW::mousePressEvent() single click on an edge "; QGraphicsView::mousePressEvent(e); return; } @@ -875,6 +1191,9 @@ void GraphicsWidget::mousePressEvent( QMouseEvent * e ) { qDebug() << "GW::mousePressEvent() Right-click on empty space "; emit openContextMenu(p); } + else { + emit userClickOnEmptySpace(); + } QGraphicsView::mousePressEvent(e); } @@ -895,6 +1214,12 @@ void GraphicsWidget::mouseReleaseEvent( QMouseEvent * e ) { Q_UNUSED(node); QGraphicsView::mouseReleaseEvent(e); } + if (Edge *edge= qgraphicsitem_cast(item)) { + Q_UNUSED(edge); + qDebug() << "GW::mouseReleaseEvent() on an edge "; + QGraphicsView::mouseReleaseEvent(e); + return; + } } else{ qDebug() << "GW::mouseReleaseEvent() on empty space. "; @@ -917,89 +1242,196 @@ void GraphicsWidget::mouseReleaseEvent( QMouseEvent * e ) { It passes delta as new m_scale */ void GraphicsWidget::wheelEvent(QWheelEvent *e) { + bool ctrlKey = (e->modifiers() == Qt::ControlModifier); qDebug("GW: Mouse wheel event"); qDebug() << "GW: delta = " << e->delta(); - float m_scale = e->delta() / qreal(600); - qDebug("GW: m_scale = %f", m_scale); - if ( m_scale > 0) - zoomIn(); - else if ( m_scale < 0) - zoomOut(); - else m_scale=1; + if (ctrlKey) { + float m_scale = e->delta() / qreal(600); + qDebug("GW: m_scale = %f", m_scale); + if ( m_scale > 0) + zoomIn(1); + else if ( m_scale < 0) + zoomOut(1); + else m_scale=1; + } + } -/** - Called from MW magnifier widgets -*/ -void GraphicsWidget::zoomOut (){ - if (zoomIndex > 0) { - zoomIndex--; - changeZoom(zoomIndex); +/** + * @brief GraphicsWidget::zoomOut + * @param level + * Called from MW magnifier button + */ +void GraphicsWidget::zoomOut (int level){ + + qDebug() << "GW: ZoomOut(): zoom index "<< m_zoomIndex + << " - level " << level; + m_zoomIndex-=level; + if (m_zoomIndex <= 0) { + m_zoomIndex = 0; } - qDebug("GW: ZoomOut() index %i", zoomIndex); - emit zoomChanged(zoomIndex); -} + emit zoomChanged(m_zoomIndex); +} -/** - Called from MW magnifier widgets -*/ -void GraphicsWidget::zoomIn(){ - qDebug("GW: ZoomIn()"); - if (zoomIndex < 6) { - zoomIndex++; - changeZoom(zoomIndex); + + +/** + * @brief GraphicsWidget::zoomIn + * @param level + * Called from MW magnifier button + */ +void GraphicsWidget::zoomIn(int level){ + + qDebug() << "GW: ZoomIn(): index "<< m_zoomIndex << " + level " << level; + m_zoomIndex+=level; + if (m_zoomIndex > 500) { + m_zoomIndex=500; } - qDebug("GW: ZoomIn() index %i", zoomIndex); - emit zoomChanged(zoomIndex); + if (m_zoomIndex < 0) { + m_zoomIndex = 0; + } + emit zoomChanged(m_zoomIndex); } + + + /** - Initiated from MW zoomCombo widget to zoom in or out. -*/ -void GraphicsWidget::changeZoom(int value) { - double scaleFactor = 0.25; - scaleFactor *= (value + 1); - m_currentScaleFactor = scaleFactor; + * @brief GraphicsWidget::changeMatrixScale + * @param value + * Initiated from MW zoomSlider and rotateSlider widgets + */ +void GraphicsWidget::changeMatrixScale(int value) { + transformationActive = true; + qreal scaleFactor = pow(qreal(2), ( value - 250) / qreal(50) ); + m_currentScaleFactor = scaleFactor ; + qDebug() << "GW: changeMatrixScale(): value " << value + << " m_currentScaleFactor " << m_currentScaleFactor + << " m_currentRotationAngle " << m_currentRotationAngle; + resetMatrix(); - this->scale(scaleFactor, scaleFactor); + scale(m_currentScaleFactor, m_currentScaleFactor); rotate(m_currentRotationAngle); + +} + + + +void GraphicsWidget::rotateLeft(){ + m_currentRotationAngle-=5; + emit rotationChanged(m_currentRotationAngle); } +void GraphicsWidget::rotateRight() { + m_currentRotationAngle+=5; + emit rotationChanged(m_currentRotationAngle); +} -void GraphicsWidget::rot(int angle){ - qDebug("rotating"); +/** + * @brief GraphicsWidget::changeMatrixRotation + * @param angle + */ +void GraphicsWidget::changeMatrixRotation(int angle){ + transformationActive = true; m_currentRotationAngle = angle; + qDebug() << "GW: changeMatrixRotation(): angle " << angle + << " m_currentRotationAngle " << m_currentRotationAngle + << " m_currentScaleFactor " << m_currentScaleFactor; resetMatrix(); scale(m_currentScaleFactor, m_currentScaleFactor); rotate(angle); } -/** Resizing the view causes a repositioning of the nodes maintaining the same pattern*/ +/** + * @brief GraphicsWidget::reset + * Resets the transformation matrix to the identity matrix ( default zoom and scale ) + */ +void GraphicsWidget::reset() { + m_currentRotationAngle=0; + m_currentScaleFactor = 1; + m_zoomIndex=250; + emit zoomChanged(m_zoomIndex); + emit rotationChanged(m_currentRotationAngle); +} + + +/** + * @brief GraphicsWidget::resizeEvent + * @param e + * Resizing the view causes a repositioning of the nodes maintaining proportions + */ void GraphicsWidget::resizeEvent( QResizeEvent *e ) { - Q_UNUSED(e); - // qDebug ("GraphicsWidget: resizeEvent"); - // int w=e->size().width(); - // int h=e->size().height(); - // int w0=e->oldSize().width(); - // int h0=e->oldSize().height(); - // qreal fX= (double)(w)/(double)(w0); - // qreal fY= (double)(h)/(double)(h0); - // foreach (QGraphicsItem *item, scene()->items()) { - // qDebug ("item will move by %f, %f", fX, fY); - // if (Node *node = qgraphicsitem_cast(item) ) { - // qDebug("Node original position %f, %f", item->x(), item->y()); - // qDebug("Node will move to %f, %f",item->x()*fX, item->y()*fY); - // node->setPos(mapToScene(item->x()*fX, item->y()*fY)); - // } - // else item->setPos(mapToScene(item->x()*fX, item->y()*fY)); - // } - // emit windowResized(w, h); + if (transformationActive) { + transformationActive = false; + return; + } + int w=e->size().width(); + int h=e->size().height(); + int w0=e->oldSize().width(); + int h0=e->oldSize().height(); + fX= (double)(w)/(double)(w0); + fY= (double)(h)/(double)(h0); + factor = ( fX < fY ) ? fX: fY; + qDebug () << "GW::resizeEvent - old size: (" + << w0 << "," << h0 + << ") - new size: (" << w << "," << h << ")" + << " fX,fY " << fX << ","<< fY; + foreach (QGraphicsItem *item, scene()->items()) { + if (Node *node = qgraphicsitem_cast(item) ) { + qDebug()<< "GW::resizeEvent - Node " << node->nodeNumber() + << " original position (" + << item->x() << "," << item->y() + << ") - will move to (" + << item->x()*fX << ", " << item->y()*fY << ")" ; + node->setPos(mapToScene(item->x()*fX, item->y()*fY)); + } + if ( (item)->type() == TypeGuide ){ + if (Guide *guide = qgraphicsitem_cast (item) ) { + if (guide->isCircle()) { + guide->die(); + guide->deleteLater (); + delete item; + +// qDebug()<< "GW::resizeEvent - Circle Guide " +// << " original position (" +// << guide->x() << "," << guide->y() +// << ") - radius " << guide->radius() +// << ") - will move to (" +// << guide->x()*fX << ", " << guide->y()*fY << ")" +// << " new radius " << guide->radius() * factor; +// guide->setCircle( +// mapToScene(guide->pos().x()*fX, +// guide->pos().y()*fY), +// guide->radius() * factor); + } + else { + qDebug()<< "GW::resizeEvent - Horizontal Guide " + << " original position (" + << guide->x() << "," << guide->y() + << ") - width " << guide->width() + << ") - will move to (" + << guide->x()*fX << ", " << guide->y()*fY << ")" + << " new width " << (int) ceil( (guide->width() *fX )); + guide->setHorizontalLine( + mapToScene(guide->pos().x()*fX, + guide->pos().y()*fY), + (int) ceil( (guide->width() *fX ))); + } + } + } + //else item->setPos(mapToScene(item->x()*fX, item->y()*fY)); + } + //update the scene width and height with that of the graphicsWidget + scene()->setSceneRect(0, 0, (qreal) ( w ), (qreal) ( h ) ); + qDebug() << "GW::resizeEvent - scene: (" + << scene()->width() << "," << scene()->height() << ")"; + emit resized( w , h ); } diff --git a/src/graphicswidget.h b/src/graphicswidget.h index a712b48d..5234f25a 100755 --- a/src/graphicswidget.h +++ b/src/graphicswidget.h @@ -5,7 +5,7 @@ graphicswidget.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -39,6 +39,7 @@ class NodeNumber; class NodeLabel; class Guide; class EdgeWeight; +class EdgeLabel; typedef QHash H_StrToEdge; typedef QHash H_NumToNode; @@ -60,21 +61,23 @@ class GraphicsWidget : public QGraphicsView { void selectNone(); void removeItem(Edge*); + void removeItem(EdgeWeight *edgeWeight); + void removeItem(EdgeLabel *edgeLabel); void removeItem(Node*); void removeItem(NodeNumber*); void removeItem(NodeLabel*); - void nodeMoved(int, int, int); + + void nodeMoved(const int &number, const int &x, const int &y); void setInitNodeColor(QString); void setInitLinkColor(QString); void setInitNodeSize(int); void setInitNumberDistance(int); void setInitLabelDistance(int); + void setInitZoomIndex (int); void setNumbersInsideNodes(bool); - bool setEdgeWeight(int, int, float); - void setAllItemsVisibility(int, bool); void removeAllItems(int); @@ -87,55 +90,82 @@ class GraphicsWidget : public QGraphicsView { void paintEvent ( QPaintEvent * event ); public slots: - void changeRelation(int relation); - - void drawNode( int i, int size, QString aColor, - QString nColor, int nSize, - QString label, QString lColor, int lSize, - QPointF p, - QString nodeShape, - bool showLabels, bool labelIn, bool showNumbers + void relationSet(int relation); + + void drawNode( const int &num, const int &nodeSize, + const QString &nodeShape, const QString &nodeColor, + const bool &showNumbers,const bool &numberInsideNode, + const QString &numberColor, const int &numberSize, + const bool &showLabels, const QString &nodeLabel, + const QString &labelColor, const int &labelSize, + const QPointF &p ); - void eraseNode(long int doomedJim); + void eraseNode(const long int &number); void setNodeVisibility(long int, bool ); //Called from Graph via MW - bool setNodeColor(long int, QString); - bool setNodeLabel(long int , QString ); - void openNodeContextMenu(); void nodeClicked(Node *); - void moveNode(int, qreal, qreal); //Called from Graph when creating random nets. - bool setNodeSize(long int, int size=0); - void setAllNodeSize(int size=0); + void moveNode(const int &num, const qreal &x, const qreal &y); //Called from Graph when creating random nets. + + bool setNodeSize(const long int &nodeNumber, const int &size=0); + void setAllNodeSize(const int &size=0); + + bool setNodeShape(const long int &nodeNumber, const QString &shape); + bool setNodeColor(const long int &, const QString &color); - void drawEdge(int, int, float, bool, bool, QString, bool); - void eraseEdge(int, int); + void setNodeNumberVisibility(const bool &toggle); + bool setNodeNumberSize(const long int &, const int &size=0); + bool setNodeNumberDistance(const long int &, const int &distance=0); + + void setNodeLabelsVisibility(const bool &toggle); + bool setNodeLabelSize(const long int &, const int &size=0); + bool setNodeLabel(long int , QString ); + bool setNodeLabelDistance(const long int &, const int &distance=0); + + void drawEdge(const int &source, const int &target, + const float &weight, + const QString &label="", + const QString &color="black", + const int &type=0, + const bool &drawArrows=true, + const bool &bezier=false, + const bool &weightNumbers=false); + void eraseEdge(const long int &source, const long int &target); void setEdgeVisibility (int relation, int, int, bool); - void setEdgeColor(long int, long int, QString); + bool setEdgeUndirected(const long int &, const long int &, const float &); + bool setEdgeWeight(const long int &, const long int &, const float &); + void setEdgeLabel(const long int &, const long int&, const QString &); + void setEdgeColor(const long int &, const long int&, const QString &); void edgeClicked(Edge *); void openEdgeContextMenu(); + void setEdgeWeightNumbersVisibility (const bool &toggle); + void setEdgeLabelsVisibility(const bool &toggle); - void changeZoom(const int value); void startEdge(Node *node); - void drawEdgeReciprocal(int, int); - void unmakeEdgeReciprocal(int, int); void clearGuides(); - void addGuideCircle( int x0, int y0, int radius); - void addGuideHLine(int y0); - void zoomIn(); - void zoomOut(); - void rot(int angle); + void addGuideCircle( const double&x0, const double&y0, const double&radius); + void addGuideHLine(const double &y0); + + void zoomIn(int level = 1); + void zoomOut(int level = 1); + void rotateLeft(); + void rotateRight(); + void changeMatrixScale(const int value); + void changeMatrixRotation(int angle); + void reset(); signals: - void windowResized(int,int); - void userDoubleClicked(int, QPointF); - void userMiddleClicked(int, int, float); + void userDoubleClickNewNode(const QPointF &); + void userMiddleClicked(const int &, const int &, const float &); + void userClickOnEmptySpace(); void openNodeMenu(); void openEdgeMenu(); void openContextMenu(const QPointF p); - void updateNodeCoords(int, int, int); + void updateNodeCoords(const int &, const int &, const int &); void selectedNode(Node *); void selectedEdge(Edge *); - void zoomChanged(int); + void zoomChanged(const int); + void rotationChanged(const int); + void resized(const int, const int); @@ -143,17 +173,18 @@ public slots: H_NumToNode nodeHash; //This is used in drawEdge() method H_StrToEdge edgesHash; // helper hash to easily find edges int m_curRelation; - int timerId, layoutType, m_nodeSize, m_numberDistance, m_labelDistance; + int m_nodeSize, m_numberDistance, m_labelDistance; double m_currentScaleFactor; + qreal fX,fY, factor; int m_currentRotationAngle; - int zoomIndex, markedNodeOrigSize,markedEdgeSourceOrigSize, markedEdgeTargetOrigSize; + int m_zoomIndex, markedNodeOrigSize,markedEdgeSourceOrigSize, markedEdgeTargetOrigSize; QString m_nodeLabel, m_numberColor, m_nodeColor, m_labelColor, m_linkColor; - bool secondDoubleClick, dynamicMovement, markedNodeExist, markedEdgeExist; + QString edgeName; + bool secondDoubleClick, markedNodeExist, markedEdgeExist; QGraphicsItem *moving; - QPointF startPoint, endPoint; Node *firstNode, *secondNode, *markedNode1, *markedEdgeSource; Node *markedEdgeTarget, *tempNode ; - + bool transformationActive; }; #endif diff --git a/src/guide.cpp b/src/guide.cpp index 90bc2ff8..56a91bfc 100755 --- a/src/guide.cpp +++ b/src/guide.cpp @@ -5,7 +5,7 @@ Guide.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -27,56 +27,88 @@ #include "guide.h" #include "graphicswidget.h" -Guide::Guide ( GraphicsWidget *gw, int x0, int y0, int radius ) : graphicsWidget ( gw ){ - graphicsWidget->scene()->addItem ( this ); - m_x0=x0; - m_y0=y0; - m_radius=radius; - setZValue ( 250 ); - circle=true; +Guide::Guide ( GraphicsWidget *gw, + const double &x0, + const double &y0, + const double &radius ) : graphicsWidget ( gw ){ + graphicsWidget->scene()->addItem ( this ); + m_radius=radius; + setZValue ( 250 ); + circle=true; + setPos(x0, y0); } -Guide::Guide ( GraphicsWidget *gw, int y0, int w) : graphicsWidget ( gw ){ - graphicsWidget->scene()->addItem ( this ); - m_y0=y0; - width= w; - setZValue ( 250 ); - circle=false; +Guide::Guide ( GraphicsWidget *gw, + const double &y0, const int &width) + : graphicsWidget ( gw ){ + graphicsWidget->scene()->addItem ( this ); + setPos(0, y0); + m_width= width; + setZValue ( 250 ); + circle=false; } + +double Guide::radius() { + return m_radius; +} + +bool Guide::isCircle() { + return (circle); +} + +void Guide::setCircle(const QPointF ¢er, + const double &radius ) { + setPos(center); + m_radius=radius; + circle = true; + update(); +} + +void Guide::setHorizontalLine(const QPointF &origin, const int &width){ + setPos(origin); + m_width= width; + circle=false; + update(); +} + +int Guide::width() { + return m_width; +} + /** Returns the bounding rectangle of the background circle*/ QRectF Guide::boundingRect() const { if (circle) { - return QRectF ( m_x0 - m_radius-1, m_y0 - m_radius-1, m_x0 + 2 * m_radius + 1, m_y0 + 2* m_radius +1 ); - } - else { - return QRectF ( 1, m_y0 -1, width, m_y0 + 1 ); - } + return QRectF ( - m_radius-1, - m_radius-1, + 2 * m_radius + 1, + 2* m_radius +1 ); + } + else { + return QRectF ( 1, -1, m_width, + 1 ); + } } void Guide::paint ( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * ){ - Q_UNUSED(option); - painter->setPen ( QPen ( QColor ( "red" ), 1, Qt::DotLine ) ); - if (circle) { - painter->drawEllipse ( QPoint(m_x0, m_y0), m_radius, m_radius ); - } - else { - painter->drawLine ( 10 , m_y0, width-10 , m_y0); - } + Q_UNUSED(option); + painter->setPen ( QPen ( QColor ( "red" ), 1, Qt::DotLine ) ); + if (circle) { + painter->drawEllipse ( QPointF(0,0), m_radius, m_radius ); + } + else { + painter->drawLine ( 0 , 0, m_width , 0); + } } void Guide::die (){ - this->prepareGeometryChange(); - this->hide(); - this->update(); - graphicsWidget->scene()->removeItem(this); - this->update(); + this->prepareGeometryChange(); + this->hide(); + this->update(); + graphicsWidget->scene()->removeItem(this); + this->update(); } diff --git a/src/guide.h b/src/guide.h index fb10d84a..5b8328a6 100755 --- a/src/guide.h +++ b/src/guide.h @@ -5,7 +5,7 @@ Guide.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -35,16 +35,23 @@ class GraphicsWidget; -static const int TypeGuide = QGraphicsItem::UserType+6; +static const int TypeGuide = QGraphicsItem::UserType+7; -class Guide : public QObject, public QGraphicsItem { - Q_OBJECT - Q_INTERFACES (QGraphicsItem) +class Guide : public QObject, public QGraphicsItem { + Q_OBJECT + Q_INTERFACES (QGraphicsItem) public: - Guide(GraphicsWidget *, int, int, int ); - Guide(GraphicsWidget *, int, int ); - enum { Type = UserType + 6 }; + Guide(GraphicsWidget *, + const double &x0, const double &y0, const double &radius ); + Guide(GraphicsWidget *, + const double &y0, const int &width); + bool isCircle(); + void setCircle(const QPointF ¢er, const double &radius) ; + void setHorizontalLine(const QPointF &origin, const int &width) ; + double radius(); + int width(); + enum { Type = UserType + 7 }; int type() const { return Type; } void die(); @@ -55,7 +62,8 @@ class Guide : public QObject, public QGraphicsItem { private: GraphicsWidget *graphicsWidget; - int m_x0, m_y0, m_radius, width; + double m_radius; + int m_width; bool circle; }; diff --git a/src/images/appsettings.png b/src/images/appsettings.png new file mode 100644 index 00000000..55aebda8 Binary files /dev/null and b/src/images/appsettings.png differ diff --git a/src/images/bugs.png b/src/images/bugs.png new file mode 100644 index 00000000..f769a3d1 Binary files /dev/null and b/src/images/bugs.png differ diff --git a/src/images/download.png b/src/images/download.png new file mode 100644 index 00000000..ec888b8d Binary files /dev/null and b/src/images/download.png differ diff --git a/src/images/edgeweight.png b/src/images/edgeweight.png new file mode 100644 index 00000000..a64ff363 Binary files /dev/null and b/src/images/edgeweight.png differ diff --git a/src/images/help-hint.png b/src/images/help-hint.png new file mode 100644 index 00000000..209f1d28 Binary files /dev/null and b/src/images/help-hint.png differ diff --git a/src/images/help.png b/src/images/help.png index f05d9168..0197ff7a 100644 Binary files a/src/images/help.png and b/src/images/help.png differ diff --git a/src/images/image.png b/src/images/image.png new file mode 100644 index 00000000..489282b0 Binary files /dev/null and b/src/images/image.png differ diff --git a/src/images/pdf.png b/src/images/pdf.png new file mode 100644 index 00000000..8f08cb99 Binary files /dev/null and b/src/images/pdf.png differ diff --git a/src/images/qt.png b/src/images/qt.png new file mode 100644 index 00000000..f05d9168 Binary files /dev/null and b/src/images/qt.png differ diff --git a/src/images/random.png b/src/images/random.png index 972501b1..ceb4cf58 100644 Binary files a/src/images/random.png and b/src/images/random.png differ diff --git a/src/images/reset.png b/src/images/reset.png new file mode 100644 index 00000000..8cfb2d55 Binary files /dev/null and b/src/images/reset.png differ diff --git a/src/images/rotateleft.png b/src/images/rotateleft.png new file mode 100644 index 00000000..4dc4af40 Binary files /dev/null and b/src/images/rotateleft.png differ diff --git a/src/images/rotateright.png b/src/images/rotateright.png new file mode 100644 index 00000000..62194d92 Binary files /dev/null and b/src/images/rotateright.png differ diff --git a/src/images/socnetv-logo.png b/src/images/socnetv-logo.png new file mode 100644 index 00000000..0b3e1501 Binary files /dev/null and b/src/images/socnetv-logo.png differ diff --git a/src/images/spider.png b/src/images/spider.png new file mode 100644 index 00000000..2827fa14 Binary files /dev/null and b/src/images/spider.png differ diff --git a/src/images/star.png b/src/images/star.png new file mode 100644 index 00000000..2cb6cb7a Binary files /dev/null and b/src/images/star.png differ diff --git a/src/images/svg.png b/src/images/svg.png new file mode 100644 index 00000000..1274a832 Binary files /dev/null and b/src/images/svg.png differ diff --git a/src/images/zoomin.png b/src/images/zoomin.png index 8b0daeea..ab819625 100644 Binary files a/src/images/zoomin.png and b/src/images/zoomin.png differ diff --git a/src/images/zoomout.png b/src/images/zoomout.png index 1575dd24..19a85c82 100644 Binary files a/src/images/zoomout.png and b/src/images/zoomout.png differ diff --git a/src/main.cpp b/src/main.cpp index 94e2372c..d7bc7dfe 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,7 @@ main.cpp - description ------------------- begin : 9 21:10:04 EET 2005 - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -51,10 +51,10 @@ int main(int argc, char *argv[]) QString option; if ( argc > 1 ) { option = argv[1]; - if (option=="--help" || option=="-h" || option=="--h" ) { + if (option=="--help" || option=="-h" || option=="--h" || option=="-help" ) { cout<<"\nSocial Network Visualizer v." << qPrintable(VERSION)<< "\n" <<"\nUsage: socnetv [flags] [file]\n" - <<"-h, --help Displayes this help message\n" + <<"-h, --help Displays this help message\n" <<"-V, --version Displays version number\n\n" <<"You can load a network from a file using \n" <<"socnetv file.net \n" diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index bd89a6ab..250e518f 100755 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -5,7 +5,7 @@ - mainwindow.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -51,23 +51,32 @@ #include "randerdosrenyidialog.h" #include "randsmallworlddialog.h" #include "randscalefreedialog.h" +#include "settingsdialog.h" -bool printDebug=false; +bool printDebug = false; void myMessageOutput ( - QtMsgType type, const QMessageLogContext &context, const QString &msg ) + QtMsgType type, const QMessageLogContext &context, const QString &msg) { QByteArray localMsg = msg.toLocal8Bit(); Q_UNUSED(context); - if (printDebug) + if ( printDebug ) switch ( type ) { case QtDebugMsg: fprintf( stderr, "Debug: %s\n", localMsg.constData() ); break; + +#if QT_VERSION >= 0x050500 + case QtInfoMsg: + fprintf( stderr, "Info: %s\n", localMsg.constData() ); + break; + +#endif + case QtWarningMsg: fprintf( stderr, "Warning: %s\n", localMsg.constData() ); break; @@ -77,510 +86,632 @@ void myMessageOutput ( case QtCriticalMsg: fprintf( stderr, "Critical: %s\n", localMsg.constData() ); abort(); // deliberately core dump + } } -/** MainWindow contruction method **/ -MainWindow::MainWindow(const QString & m_fileName) { - - qInstallMessageHandler( myMessageOutput ); - - setWindowIcon (QIcon(":/images/socnetv.png")); - - /** inits that invoke all other construction parts **/ - initActions(); //register and construct menu Actions - initMenuBar(); //construct menu - initToolBar(); //build the toolbar - initStatusBar(); //and now add the status bar. - initToolBox(); //finally, build the toolbox - //and fill a stringList with all X-supported color names - colorList = QColor::colorNames(); - //set MW minimum size, before creating scene and canvas - this->setMinimumSize(900,600); +/** + * @brief MainWindow::MainWindow + * @param m_fileName + * MainWindow contruction method + */ +MainWindow::MainWindow(const QString & m_fileName) { - initView(); //create the canvas + appSettings = initSettings(); - //Connect some signals to/from the canvas and the Graph - connect( graphicsWidget, SIGNAL( selectedNode(Node*) ), - this, SLOT( nodeInfoStatusBar(Node*) ) ); + qInstallMessageHandler( myMessageOutput); - connect( graphicsWidget, SIGNAL( selectedEdge(Edge*) ), - this, SLOT ( edgeInfoStatusBar(Edge*) ) ); + setWindowIcon (QIcon(":/images/socnetv.png")); - connect( graphicsWidget, SIGNAL( windowResized(int, int)), - this, SLOT( windowInfoStatusBar(int,int)) ); + this->setMinimumSize(1024,750); //set MW minimum size, before creating canvas - connect( graphicsWidget, SIGNAL( windowResized(int, int)), - &activeGraph, SLOT( setCanvasDimensions(int,int)) ); + initView(); //init our network "canvas" - connect( graphicsWidget, SIGNAL( userDoubleClicked(int, QPointF) ), - this, SLOT( addNodeWithMouse(int,QPointF) ) ) ; + /** functions that invoke all other construction parts **/ + initActions(); //register and construct menu Actions - connect( graphicsWidget, SIGNAL( userMiddleClicked(int, int, float) ), - this, SLOT( addEdge(int, int, float) ) ); + initMenuBar(); //construct the menu + initToolBar(); //build the toolbar - connect( graphicsWidget, SIGNAL( openNodeMenu() ), - this, SLOT( openNodeContextMenu() ) ) ; + initStatusBar(); //add the status bar - connect( graphicsWidget, SIGNAL( openEdgeMenu() ), - this, SLOT( openEdgeContextMenu() ) ) ; + initToolBox(); //build the toolbox - connect (graphicsWidget, &GraphicsWidget::openContextMenu, - this, &MainWindow::openContextMenu); + initWindowLayout(); //init the application window, set layout etc - connect( graphicsWidget, SIGNAL(updateNodeCoords(int, int, int)), - this, SLOT( updateNodeCoords(int, int, int) ) ); + initSignalSlots(); //connect signals and slots between app components - connect( graphicsWidget, SIGNAL(zoomChanged(int)), - zoomCombo, SLOT( setCurrentIndex(int)) ); + /* load and initialise default network parameters */ + initNet(); - connect( &activeGraph, SIGNAL( addGuideCircle(int, int, int) ), - graphicsWidget, SLOT( addGuideCircle(int, int, int) ) ) ; + // Check if user-provided network file on startup + qDebug() << "MW::MainWindow() Checking if user provided file on startup..."; + if (!m_fileName.isEmpty()) { + slotNetworkFileChoose( m_fileName ); + } - connect( &activeGraph, SIGNAL( addGuideHLine(int) ), - graphicsWidget, SLOT( addGuideHLine(int) ) ) ; + graphicsWidget->setFocus(); - connect( &activeGraph, SIGNAL( moveNode(int, qreal, qreal) ), - graphicsWidget, SLOT( moveNode(int, qreal, qreal) ) ) ; + statusMessage( tr("Welcome to Social Network Visualizer, Version ")+VERSION); +} - connect( &activeGraph, - SIGNAL( - drawNode( int ,int, QString, QString, int, QString, QString, - int, QPointF, QString, bool, bool, bool) - ), - graphicsWidget, - SLOT( - drawNode( int ,int, QString, QString, int, QString, QString, - int, QPointF, QString, bool, bool, bool) - ) - ) ; - connect( &activeGraph, SIGNAL( eraseEdge(int, int)), - graphicsWidget, SLOT( eraseEdge(int, int) ) ); - connect( &activeGraph, SIGNAL( graphChanged() ), - this, SLOT( graphChanged() ) ) ; +MainWindow::~MainWindow() { + qDebug() << "MW::~MainWindow() Destruct function running..."; + delete printer; + delete scene; + delete graphicsWidget; + qDebug() << "MW::~MainWindow() Destruct function finished - bye!"; +} - connect( &activeGraph, - SIGNAL( - signalFileType(int , QString , int , int, bool) ), - this, - SLOT( fileType(int , QString , int , int, bool) ) - ) ; - connect( &activeGraph, - SIGNAL( - drawEdge( int, int, float, bool, bool, QString, bool) - ), - graphicsWidget, - SLOT( - drawEdge( int, int,float, bool, bool, QString, bool) - ) ) ; - connect( &activeGraph, SIGNAL( drawEdgeReciprocal(int, int) ), - graphicsWidget, SLOT( drawEdgeReciprocal(int, int) ) ); +/** + * @brief MainWindow::initSettings() + * Init default (or user-defined) app settings + * + */ +QMap MainWindow::initSettings(){ + qDebug()<< "MW::initSettings"; - connect( &activeGraph, SIGNAL( changeEdgeColor(long int,long int,QString)), - graphicsWidget, SLOT( setEdgeColor(long int,long int,QString) ) ); + printDebug = false; // comment it to stop debug override + firstTime=true; // becomes false on user IO - connect( &activeGraph, SIGNAL( statusMessage (QString) ), - this, SLOT( statusMessage (QString) ) ) ; + // Create fortune cookies and tips + createFortuneCookies(); + slotHelpCreateTips(); - connect( &activeGraph, SIGNAL( describeDataset (QString) ), - this, SLOT( showMessageToUser (QString) ) ) ; + // Call slotNetworkAvailableTextCodecs to setup a list of all supported codecs + qDebug() << "MW::initSettings - calling slotNetworkAvailableTextCodecs" ; + slotNetworkAvailableTextCodecs(); - connect( &activeGraph, SIGNAL( eraseNode(long int) ), - graphicsWidget, SLOT( eraseNode(long int) ) ); + qDebug() << "MW::initSettings - creating PreviewForm object and setting codecs list" ; + previewForm = new PreviewForm(this); + previewForm->setCodecList(codecs); - connect( &activeGraph, &Graph::signalNodeSizesByInDegree, - this, &MainWindow::slotLayoutNodeSizesByInDegree ); + connect (previewForm, &PreviewForm::loadNetworkFileWithCodec, + this, &MainWindow::slotNetworkFileLoad ); + qDebug() << "MW::initSettings - creating default settings" ; + settingsDir = QDir::homePath() +QDir::separator() + "socnetv-data" + QDir::separator() ; + settingsFilePath = settingsDir + "settings.conf"; - //connect some signals/slots with MW widgets - connect( addNodeBt,SIGNAL(clicked()), this, SLOT( addNode() ) ); + // initially they are the same, but dataDir may be changed by the user + QString dataDir= settingsDir ; - connect( addEdgeBt,SIGNAL(clicked()), this, SLOT( slotAddEdge() ) ); + maxNodes=5000; //Max nodes used by createRandomNetwork dialogues - connect( removeNodeBt,SIGNAL(clicked()), this, SLOT( slotRemoveNode() ) ); + // hard-coded initial settings to use only on first app load + // when there are no user defined values + appSettings["initNodeSize"]= "10"; + appSettings["initNodeColor"]="red"; + appSettings["initNodeShape"]="circle"; + + appSettings["initNodeNumbersVisibility"] = "true"; + appSettings["initNodeNumberSize"]="0"; + appSettings["initNodeNumberColor"]="#333"; + appSettings["initNodeNumbersInside"] = "true"; + appSettings["initNodeNumberDistance"] = "2"; + + appSettings["initNodeLabelsVisibility"] = "false"; + appSettings["initNodeLabelSize"]="6"; + appSettings["initNodeLabelColor"]="#00aa00"; + appSettings["initNodeLabelDistance"] = "6"; + + appSettings["initEdgesVisibility"]="true"; + appSettings["initEdgeShape"]="line"; //bezier + appSettings["initEdgeColor"]="black"; + appSettings["initEdgeColorNegative"]="red"; + appSettings["initEdgeArrows"]="true"; + appSettings["initEdgeThicknessPerWeight"]="true"; + appSettings["initEdgeWeightNumbersVisibility"]="false"; + appSettings["initEdgeWeightNumberSize"] = "7"; + appSettings["initEdgeWeightNumberColor"] = "#00aa00"; + appSettings["initEdgeLabelsVisibility"] = "false"; + appSettings["considerWeights"]="false"; + appSettings["inverseWeights"]="false"; + appSettings["askedAboutWeights"]="false"; + + appSettings["initBackgroundColor"]="white"; //"gainsboro"; + appSettings["initBackgroundImage"]=""; + appSettings["printDebug"] = (printDebug) ? "true" : "false"; + appSettings["showProgressBar"] = "true"; + appSettings["showToolBar"] = "true"; + appSettings["showStatusBar"] = "true"; + appSettings["antialiasing"] = "true"; + appSettings["dataDir"]= dataDir ; + appSettings["lastUsedDirPath"]= dataDir ; + appSettings["showRightPanel"] = "true"; + appSettings["showLeftPanel"] = "true"; + appSettings["printLogo"] = "true"; + appSettings["randomErdosEdgeProbability"] = "0.04"; + + // Try to load settings configuration file + // First check if our settings folder exist + QDir socnetvDir(settingsDir); + if ( !socnetvDir.exists() ) { + qDebug() << "MW::initSettings - dir does not exist - create it"; + socnetvDir.mkdir(settingsDir); + } + // Then check if the conf file exists inside the folder + qDebug () << "MW::initSettings - checking for settings file: " + << settingsFilePath; + + if (!socnetvDir.exists(settingsFilePath)) { + saveSettings(); + } + else { + qDebug()<< "MW::initSettings - settings file exist - Reading it"; + QFile file(settingsFilePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::critical(this, "File Read Error", tr("Error! \n" + "I cannot read the settings file " + "in \n" + settingsFilePath.toLocal8Bit() + + "\n" + "You can continue using SocNetV with default " + "settings but any changes to them will not " + " be saved for future sessions \n" + "Please, check permissions in your home folder " + " and conduct the developer." + ), + QMessageBox::Ok, 0); + return appSettings; + } + QTextStream in(&file); + QStringList setting; + while (!in.atEnd()) { + QString line = in.readLine(); + if (!line.isEmpty()) { + setting = line.simplified().split('='); + qDebug() << " read setting: " << setting[0].simplified() << " = " << setting[1].simplified(); + if (setting[0].simplified().startsWith("recentFile_")) + recentFiles += setting[1].simplified(); + else + appSettings.insert (setting[0].simplified() , setting[1].simplified() ); + } + } + file.close(); + } + qDebug () << "MW::initSettings() - Recent files count " << recentFiles.count() ; + // restore user setting for debug messages + printDebug = (appSettings["printDebug"] == "true") ? true:false; - connect( removeEdgeBt,SIGNAL(clicked()), this, SLOT( slotRemoveEdge() ) ); + return appSettings; +} - connect( zoomCombo, SIGNAL(currentIndexChanged(const int &)), - graphicsWidget, SLOT( changeZoom(const int &)) ); - connect( zoomOutAct, SIGNAL(triggered()), graphicsWidget, SLOT( zoomOut() ) ); - connect( zoomInAct, SIGNAL(triggered()), graphicsWidget, SLOT( zoomIn() ) ); - connect( rotateSpinBox, SIGNAL(valueChanged(int)), graphicsWidget, SLOT( rot(int) ) ); +/** + * @brief MainWindow::saveSettings + * Saves default (or user-defined) app settings + */ +void MainWindow::saveSettings() { + qDebug () << "MW::saveSettings to "<< settingsFilePath; + QFile file(settingsFilePath); + + // application settings file does not exist - create it + // this must be the first time SocNetV runs in this computer + // or the user might have deleted seetings file. + if (!file.open(QIODevice::WriteOnly ) ) { + QMessageBox::critical(this, + "File Write Error", + tr("Error! \n" + "I cannot write the new settings file " + "in \n" + settingsFilePath.toLocal8Bit() + + "\n" + "You can continue using SocNetV with default " + "settings but any changes to them will not " + " be saved for future sessions \n" + "Please, check permissions in your home folder " + " and conduct the developer." + ), + QMessageBox::Ok, 0); + return; + } + qDebug()<< "MW::saveSettings - settings file does not exist - Creating it"; + QTextStream out(&file); + qDebug()<< "MW::saveSettings - writing settings to settings file first "; + QMap::const_iterator it = appSettings.constBegin(); + while (it != appSettings.constEnd()) { + qDebug() << " setting: " << it.key() << " = " << it.value(); + out << it.key() << " = " << it.value() << endl; + ++it; + } - connect( nextRelationAct, SIGNAL(triggered()), this, SLOT( nextRelation() ) ); - connect( prevRelationAct, SIGNAL(triggered()), this, SLOT( prevRelation() ) ); - connect( addRelationAct, SIGNAL(triggered()), this, SLOT( addRelation() ) ); - connect( changeRelationCombo , SIGNAL( currentIndexChanged(int) ) , - &activeGraph, SLOT( changeRelation(int) ) ); + // save recent files + for (int i = 0 ; i < recentFiles.size() ; ++i) { + out << "recentFile_"+ QString::number(i+1) + << " = " + << recentFiles.at(i) << endl; + } - connect( this , SIGNAL(addRelationToGraph(QString)), - &activeGraph, SLOT( addRelationFromUser(QString) ) ); + file.close(); - connect ( &activeGraph, SIGNAL(addRelationToMW(QString)), - this, SLOT(addRelation(QString))); +} - connect( &activeGraph, SIGNAL(relationChanged(int)), - graphicsWidget, SLOT( changeRelation(int)) ) ; - connect( &m_filterEdgesByWeightDialog, SIGNAL( userChoices( float, bool) ), - &activeGraph, SLOT( filterEdgesByWeight (float, bool) ) ); - connect( &m_WebCrawlerDialog, &WebCrawlerDialog::userChoices, - this, &MainWindow::slotWebCrawl ); +/** + * @brief MainWindow::slotOpenSettingsDialog + * Open Settings dialog + */ +void MainWindow::slotOpenSettingsDialog() { + qDebug() << "MW;:slotOpenSettingsDialog()"; - connect( &m_datasetSelectDialog, SIGNAL( userChoices( QString) ), - this, SLOT( slotRecreateDataSet(QString) ) ); + // build dialog - connect( &activeGraph, SIGNAL( setEdgeVisibility (int, int, int, bool) ), - graphicsWidget, SLOT( setEdgeVisibility (int, int, int, bool) ) ); + m_settingsDialog = new SettingsDialog( appSettings, this); - connect( &activeGraph, SIGNAL( setVertexVisibility(long int, bool) ), - graphicsWidget, SLOT( setNodeVisibility (long int , bool) ) ); + connect( m_settingsDialog, &SettingsDialog::saveSettings, + this, &MainWindow::saveSettings); - connect( &activeGraph, SIGNAL( setNodeSize(long int, int) ), - graphicsWidget, SLOT( setNodeSize (long int , int) ) ); + connect( m_settingsDialog, &SettingsDialog::setDebugMsgs, + this, &MainWindow::slotOptionsDebugMessages); - connect( &activeGraph, SIGNAL( setNodeShape(const long int, const QString) ), - graphicsWidget, SLOT( setNodeShape (const long int , const QString) ) ); + connect( m_settingsDialog, &SettingsDialog::setProgressBars, + this, &MainWindow::slotOptionsProgressBarVisibility); - connect( &activeGraph, SIGNAL( setNodeColor(long int,QString)) , - graphicsWidget, SLOT( setNodeColor(long int, QString) ) ); + connect( m_settingsDialog, &SettingsDialog::setAntialiasing, + this, &MainWindow::slotOptionsAntialiasing); - connect( &activeGraph, &Graph::setNodeLabel , - graphicsWidget, &GraphicsWidget::setNodeLabel ); + connect( m_settingsDialog, &SettingsDialog::setPrintLogo, + this, &MainWindow::slotOptionsEmbedLogoExporting); - connect( clearGuidesAct, SIGNAL(triggered()), - graphicsWidget, SLOT(clearGuides())); + connect( m_settingsDialog, &SettingsDialog::setBgColor, + this, &MainWindow::slotOptionsBackgroundColor); - connect(toolBoxAnalysisGeodesicsSelect, SIGNAL (currentIndexChanged(int) ), - this, SLOT(toolBoxAnalysisGeodesicsSelectChanged(int) ) ); + connect( m_settingsDialog, &SettingsDialog::setBgImage, + this, &MainWindow::slotOptionsBackgroundImage); - connect(toolBoxAnalysisConnectivitySelect, SIGNAL (currentIndexChanged(int) ), - this, SLOT(toolBoxAnalysisConnectivitySelectChanged(int) ) ); + connect( m_settingsDialog, &SettingsDialog::setToolBar, + this, &MainWindow::slotOptionsToolbarVisibility); - connect(toolBoxAnalysisClusterabilitySelect, SIGNAL (currentIndexChanged(int) ), - this, SLOT(toolBoxAnalysisClusterabilitySelectChanged(int) ) ); + connect( m_settingsDialog, &SettingsDialog::setStatusBar, + this, &MainWindow::slotOptionsStatusBarVisibility); - connect(toolBoxAnalysisProminenceSelect, SIGNAL (currentIndexChanged(int) ), - this, SLOT(toolBoxAnalysisProminenceSelectChanged(int) ) ); + connect( m_settingsDialog, &SettingsDialog::setLeftPanel, + this, &MainWindow::slotOptionsLeftPanelVisibility); + connect( m_settingsDialog, &SettingsDialog::setRightPanel, + this, &MainWindow::slotOptionsRightPanelVisibility); - connect(toolBoxLayoutByIndexButton, SIGNAL (clicked() ), - this, SLOT(toolBoxLayoutByIndexButtonPressed() ) ); + connect(m_settingsDialog, SIGNAL(setNodeColor(QColor)), + this, SLOT(slotEditNodeColorAll(QColor)) ); - connect( layoutGuidesBx, SIGNAL(stateChanged(int)), - this, SLOT(slotLayoutGuides(int))); + connect( m_settingsDialog, &SettingsDialog::setNodeShape, + this, &MainWindow::slotEditNodeShape); + connect( m_settingsDialog, &SettingsDialog::setNodeSize, + this, &MainWindow::slotEditNodeSizeAll); + connect( m_settingsDialog, &SettingsDialog::setNodeNumbersVisibility, + this, &MainWindow::slotOptionsNodeNumbersVisibility); - //create an horizontal layout for the toolbox and the canvas. - // This will be our MW layout. - QHBoxLayout *layout = new QHBoxLayout; - layout->addWidget(toolBox); //add them - layout->addWidget(graphicsWidget); - //create a dummy widget, for the above layout - QWidget *widget = new QWidget; - widget->setLayout(layout); - //now set this as central widget of MW - setCentralWidget(widget); + connect( m_settingsDialog, &SettingsDialog::setNodeNumbersInside, + this, &MainWindow::slotOptionsNodeNumbersInside); - /* - initialise default network parameters - */ - qDebug()<<" initialise default network parameters"; - initNet(); + connect( m_settingsDialog, &SettingsDialog::setNodeNumberColor, + this, &MainWindow::slotEditNodeNumbersColor); + connect( m_settingsDialog, &SettingsDialog::setNodeNumberSize, + this, &MainWindow::slotEditNodeNumberSize); - /* - * DEFAULTING HERE DOES NOT CHANGE BOOL VALUE - EVERY TIME INITNET IS CALLED - */ - bezier=false; - firstTime=true; - - graphicsWidget->setInitNodeColor(initNodeColor); - graphicsWidget->setInitNumberDistance(numberDistance); - graphicsWidget->setInitLabelDistance(labelDistance); - graphicsWidget->setInitNodeSize(initNodeSize); - graphicsWidget->setBackgroundBrush(QBrush(initBackgroundColor)); //Qt::gray - dataDir= QDir::homePath() +QDir::separator() + "socnetv-data" + QDir::separator() ; - lastUsedDirPath = "socnetv-initial-none"; - if (firstTime) { - createFortuneCookies(); - createTips(); - QDir ourDir(dataDir); - if ( !ourDir.exists() ) { - ourDir.mkdir(dataDir); - QMessageBox::information(this, "SocNetV Data Directory", - tr("SocNetV saves reports and files in the " - "directory %1") - .arg (ourDir.absolutePath()) - , QMessageBox::Ok, 0); + connect( m_settingsDialog, &SettingsDialog::setNodeNumberDistance, + this, &MainWindow::slotEditNodeNumberDistance); - } + connect( m_settingsDialog, &SettingsDialog::setNodeLabelsVisibility, + this, &MainWindow::slotOptionsNodeLabelsVisibility); - } + connect( m_settingsDialog, &SettingsDialog::setNodeLabelSize, + this, &MainWindow::slotEditNodeLabelSize); - qDebug() << "MW::MainWindow() call findCodecs" ; - findCodecs(); + connect( m_settingsDialog, &SettingsDialog::setNodeLabelColor, + this, &MainWindow::slotEditNodeLabelsColor); - qDebug() << "MW::MainWindow() create PreviewForm object and set codecs" ; - previewForm = new PreviewForm(this); - previewForm->setCodecList(codecs); + connect( m_settingsDialog, &SettingsDialog::setNodeLabelDistance, + this, &MainWindow::slotEditNodeLabelDistance); - connect (previewForm, &PreviewForm::userCodec, this, &MainWindow::userCodec ); + connect( m_settingsDialog, &SettingsDialog::setEdgesVisibility, + this, &MainWindow::slotOptionsEdgesVisibility); - qDebug() << "MW::MainWindow() Try load *graphml* file on exec time "; - if (!m_fileName.isEmpty()) - { - fileName=m_fileName; - fileNameNoPath=fileName.split ("/"); - previewNetworkFile( fileName, 0 ); - } + connect( m_settingsDialog, &SettingsDialog::setEdgeColor, + this, &MainWindow::slotEditEdgeColorAll); - graphicsWidget->setFocus(); + connect( m_settingsDialog, &SettingsDialog::setEdgeWeightNumbersVisibility, + this, &MainWindow::slotOptionsEdgeWeightNumbersVisibility); - statusMessage( tr("Welcome to Social Network Visualizer, Version ")+VERSION); + connect( m_settingsDialog, &SettingsDialog::setEdgeLabelsVisibility, + this, &MainWindow::slotOptionsEdgeLabelsVisibility); -} + // show settings dialog + m_settingsDialog->exec(); + qDebug ()<< appSettings["initBackgroundImage"] ; -MainWindow::~MainWindow() { - delete printer; - delete scene; - delete graphicsWidget; } -/** initializes all QActions of the application */ +/** + * @brief MainWindow::initActions + * Initializes ALL QActions of the application + * Take a breath, the listing below is HUGE. + */ void MainWindow::initActions(){ printer = new QPrinter; /** - File menu actions + Network menu actions */ - fileNew = new QAction(QIcon(":/images/new.png"), tr("&New"), this); - fileNew->setShortcut(tr("Ctrl+N")); - fileNew->setStatusTip(tr("Creates a new network")); - fileNew->setToolTip(tr("New network (Ctrl+N)")); - fileNew->setWhatsThis(tr("New\n\nCreates a new network")); - connect(fileNew, SIGNAL(triggered()), this, SLOT(slotCreateNew())); - - fileOpen = new QAction(QIcon(":/images/open.png"), tr("&Open"), this); - fileOpen->setShortcut(tr("Ctrl+O")); - fileOpen->setToolTip(tr("Open network (Ctrl+O)")); - fileOpen->setStatusTip(tr("Open a GraphML-formatted file of an existing network")); - fileOpen->setWhatsThis(tr("Open\n\nOpens a file of an existing network in GraphML format")); - connect(fileOpen, SIGNAL(triggered()), this, SLOT(slotImportGraphML())); - - - importPajek = new QAction( QIcon(":/images/open.png"), tr("&Pajek"), this); - importPajek->setStatusTip(tr("Import a Pajek-formatted file")); - importPajek->setWhatsThis(tr("Import Pajek \n\n Imports a network from a Pajek-formatted file")); - connect(importPajek, SIGNAL(triggered()), this, SLOT(slotImportPajek())); - - - importSM = new QAction( QIcon(":/images/open.png"), tr("&Adjacency Matrix"), this); - importSM->setStatusTip(tr("Import an Adjacency matrix file")); - importSM->setWhatsThis(tr("Import Sociomatrix \n\n Imports a network from an Adjacency matrix-formatted file")); - connect(importSM, SIGNAL(triggered()), this, SLOT(slotImportSM())); - - importDot = new QAction( QIcon(":/images/open.png"), tr("GraphViz (.dot)"), this); - importDot->setStatusTip(tr("Import an dot file")); - importDot->setWhatsThis(tr("Import GraphViz \n\n Imports a network from an GraphViz formatted file")); - connect(importDot, SIGNAL(triggered()), this, SLOT(slotImportDot())); - - - importDL = new QAction( QIcon(":/images/open.png"), tr("UCINET (.dl)..."), this); - importDL->setStatusTip(tr("Import network to a DL-formatted file (UCINET)")); - importDL->setWhatsThis(tr("Import UCINET\n\nImports a network from a DL-formatted file")); - connect(importDL, SIGNAL(triggered()), this, SLOT(slotImportDL())); - - - importList = new QAction( QIcon(":/images/open.png"), tr("&Edge list"), this); - importList->setStatusTip(tr("Import network from an edge list file. ")); - importList->setWhatsThis(tr("Import edge list\n\n" + networkNew = new QAction(QIcon(":/images/new.png"), tr("&New"), this); + networkNew->setShortcut(Qt::CTRL+Qt::Key_N); + networkNew->setStatusTip(tr("Creates a new network")); + networkNew->setToolTip(tr("New network (Ctrl+N)")); + networkNew->setWhatsThis(tr("New\n\nCreates a new network")); + connect(networkNew, SIGNAL(triggered()), this, SLOT(slotNetworkNew())); + + networkOpen = new QAction(QIcon(":/images/open.png"), tr("&Open"), this); + networkOpen->setShortcut(Qt::CTRL+Qt::Key_O); + networkOpen->setToolTip(tr("Open network (Ctrl+O)")); + networkOpen->setStatusTip(tr("Open GraphML-formatted file of an existing network")); + networkOpen->setWhatsThis(tr("Open\n\n" + "Opens a file of an existing network in GraphML format")); + connect(networkOpen, SIGNAL(triggered()), this, SLOT(slotNetworkFileChoose())); + + + for (int i = 0; i < MaxRecentFiles; ++i) { + recentFileActs[i] = new QAction(this); + recentFileActs[i]->setVisible(false); + connect(recentFileActs[i], SIGNAL(triggered()), + this, SLOT(slotNetworkFileLoadRecent())); + } + + + networkImportPajek = new QAction( QIcon(":/images/open.png"), tr("&Pajek"), this); + networkImportPajek->setStatusTip(tr("Import Pajek-formatted file")); + networkImportPajek->setWhatsThis(tr("Import Pajek \n\n" + "Imports a network from a Pajek-formatted file")); + connect(networkImportPajek, SIGNAL(triggered()), this, SLOT(slotNetworkImportPajek())); + + + networkImportSM = new QAction( QIcon(":/images/open.png"), tr("&Adjacency Matrix"), this); + networkImportSM->setStatusTip(tr("Import Adjacency matrix")); + networkImportSM->setWhatsThis(tr("Import Sociomatrix \n\n" + "Imports a network from an Adjacency matrix-formatted file")); + connect(networkImportSM, SIGNAL(triggered()), this, SLOT(slotNetworkImportSM())); + + networkImportDot = new QAction( QIcon(":/images/open.png"), tr("GraphViz (.dot)"), this); + networkImportDot->setStatusTip(tr("Import dot file")); + networkImportDot->setWhatsThis(tr("Import GraphViz \n\n " + "Imports a network from an GraphViz formatted file")); + connect(networkImportDot, SIGNAL(triggered()), + this, SLOT(slotNetworkImportDot())); + + + networkImportDL = new QAction( QIcon(":/images/open.png"), tr("UCINET (.dl)..."), this); + networkImportDL->setStatusTip(tr("ImportDL-formatted file (UCINET)")); + networkImportDL->setWhatsThis(tr("Import UCINET\n\nImports a network from a DL-formatted file")); + connect(networkImportDL, SIGNAL(triggered()), this, SLOT(slotNetworkImportDL())); + + + networkImportList = new QAction( QIcon(":/images/open.png"), tr("&Edge list"), this); + networkImportList->setStatusTip(tr("Import an edge list file. ")); + networkImportList->setWhatsThis(tr("Import edge list\n\n" "Import a network from an edgelist file. " " The file can be unvalued or valued (see manual)" )); - connect(importList, SIGNAL(triggered()), this, SLOT(slotImportEdgeList())); - - - importTwoModeSM = new QAction( QIcon(":/images/open.png"), tr("&Two Mode Sociomatrix"), this); - importTwoModeSM->setStatusTip(tr("Imports a two mode sociomatrix (affiliation network) file")); - importTwoModeSM->setWhatsThis(tr("Import Sociomatrix \n\n Imports a two mode network from a sociomatrix file. Two-mode networks are described by affiliation network matrices, where A(i,j) codes the events/organizations each actor is affiliated with.")); - connect(importTwoModeSM, SIGNAL(triggered()), this, SLOT(slotImportTwoModeSM())); - - - fileSave = new QAction(QIcon(":/images/save.png"), tr("&Save"), this); - fileSave->setShortcut(tr("Ctrl+S")); - fileSave->setToolTip(tr("Save network (Ctrl+S)")); - fileSave->setStatusTip(tr("Saves the actual network to the current file")); - fileSave->setWhatsThis(tr("Save.\n\nSaves the actual network")); - connect(fileSave, SIGNAL(triggered()), this, SLOT(slotFileSave())); - - fileSaveAs = new QAction(QIcon(":/images/save.png"), tr("Save &As..."), this); - fileSaveAs->setShortcut(tr("Ctrl+Shift+S")); - fileSaveAs->setStatusTip(tr("Saves the actual network under a new filename")); - fileSaveAs->setWhatsThis(tr("Save As\n\nSaves the actual network under a new filename")); - connect(fileSaveAs, SIGNAL(triggered()), this, SLOT(slotFileSaveAs())); - - exportBMP = new QAction(QIcon(":/images/save.png"), tr("&BMP..."), this); - exportBMP->setStatusTip(tr("Export network to a BMP image")); - exportBMP->setWhatsThis(tr("Export BMP \n\n Export network to a BMP image")); - connect(exportBMP, SIGNAL(triggered()), this, SLOT(slotExportBMP())); - - exportPNG = new QAction( QIcon(":/images/save.png"), tr("&PNG..."), this); - exportPNG->setStatusTip(tr("Export network to a PNG image")); - exportPNG->setWhatsThis(tr("Export PNG \n\n Export network to a PNG image")); - connect(exportPNG, SIGNAL(triggered()), this, SLOT(slotExportPNG())); - - - exportPDF = new QAction( QIcon(":/images/save.png"), tr("&PDF..."), this); - exportPDF->setStatusTip(tr("Export network to a PDF file")); - exportPDF->setWhatsThis(tr("Export PDF\n\n Export network to a PDF document")); - connect(exportPDF, SIGNAL(triggered()), this, SLOT(slotExportPDF())); - - exportSM = new QAction( QIcon(":/images/save.png"), tr("&Adjacency Matrix"), this); - exportSM->setStatusTip(tr("Export network to an adjacency matrix file")); - exportSM->setWhatsThis(tr("Export Sociomatrix \n\n Export network to a adjacency matrix-formatted file")); - connect(exportSM, SIGNAL(triggered()), this, SLOT(slotExportSM())); - - exportPajek = new QAction( QIcon(":/images/save.png"), tr("&Pajek"), this); - exportPajek->setStatusTip(tr("Export network to a Pajek-formatted file")); - exportPajek->setWhatsThis(tr("Export Pajek \n\n Export network to a Pajek-formatted file")); - connect(exportPajek, SIGNAL(triggered()), this, SLOT(slotExportPajek())); - - exportList = new QAction( QIcon(":/images/save.png"), tr("&List"), this); - exportList->setStatusTip(tr("Export network to a List-formatted file. ")); - exportList->setWhatsThis(tr("Export List\n\nExport network to a List-formatted file")); - connect(exportList, SIGNAL(triggered()), this, SLOT(slotExportList())); - - exportDL = new QAction( QIcon(":/images/save.png"), tr("&DL..."), this); - exportDL->setStatusTip(tr("Export network to a DL-formatted file")); - exportDL->setWhatsThis(tr("Export DL\n\nExport network to a DL-formatted")); - connect(exportDL, SIGNAL(triggered()), this, SLOT(slotExportDL())); - - exportGW = new QAction( QIcon(":/images/save.png"), tr("&GW..."), this); - exportGW->setStatusTip(tr("Export network to a GW-formatted file")); - exportGW->setWhatsThis(tr("Export\n\nExport network to a GW formatted file")); - connect(exportGW, SIGNAL(triggered()), this, SLOT(slotExportGW())); - - fileClose = new QAction( tr("&Close"), this); - fileClose->setStatusTip(tr("Closes the actual network")); - fileClose->setWhatsThis(tr("Close \n\nCloses the actual network")); - connect(fileClose, SIGNAL(triggered()), this, SLOT(slotFileClose())); - - printNetwork = new QAction(QIcon(":/images/print.png"), tr("&Print"), this); - printNetwork->setShortcut(tr("Ctrl+P")); - printNetwork->setStatusTip(tr("Prints whatever is viewable on the canvas.")); - printNetwork->setWhatsThis(tr("Printing \n\n This function prints whatever is viewable on the canvas. \nTo print the whole network, you might want to zoom-out.")); - connect(printNetwork, SIGNAL(triggered()), this, SLOT(slotPrintView())); - - fileQuit = new QAction(QIcon(":/images/exit.png"), tr("E&xit"), this); - fileQuit->setShortcut(tr("Ctrl+Q")); - fileQuit->setStatusTip(tr("Quits the application")); - fileQuit->setWhatsThis(tr("Exit\n\nQuits the application")); - connect(fileQuit, SIGNAL(triggered()), this, SLOT(close())); + connect(networkImportList, SIGNAL(triggered()), + this, SLOT(slotNetworkImportEdgeList())); + + + networkImportTwoModeSM = new QAction( QIcon(":/images/open.png"), tr("&Two Mode Sociomatrix"), this); + networkImportTwoModeSM->setStatusTip(tr("Import two-mode sociomatrix (affiliation network) file")); + networkImportTwoModeSM->setWhatsThis(tr("Import Two-Mode Sociomatrix \n\n " + "Imports a two-mode network from a sociomatrix file. " + "Two-mode networks are described by affiliation " + "network matrices, where A(i,j) codes the " + "events/organizations each actor is affiliated with.")); + connect(networkImportTwoModeSM, SIGNAL(triggered()), + this, SLOT(slotNetworkImportTwoModeSM())); + + + networkSave = new QAction(QIcon(":/images/save.png"), tr("&Save"), this); + networkSave->setShortcut(Qt::CTRL+Qt::Key_S); + networkSave->setToolTip(tr("Save network (Ctrl+S)")); + networkSave->setStatusTip(tr("Save to the current file")); + networkSave->setWhatsThis(tr("Save.\n\n" + "Saves the actual network to the current file")); + connect(networkSave, SIGNAL(triggered()), this, SLOT(slotNetworkSave())); + + networkSaveAs = new QAction(QIcon(":/images/save.png"), tr("Save &As..."), this); + networkSaveAs->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_S); + networkSaveAs->setStatusTip(tr("Save under a new filename" + "Ctrl+Shift+S")); + networkSaveAs->setWhatsThis(tr("Save As\n\n" + "Saves the actual network under a new filename")); + connect(networkSaveAs, SIGNAL(triggered()), this, SLOT(slotNetworkSaveAs())); + + networkExportBMP = new QAction(QIcon(":/images/image.png"), tr("&BMP..."), this); + networkExportBMP->setStatusTip(tr("Export to BMP image")); + networkExportBMP->setWhatsThis(tr("Export BMP \n\n Exports the network to a BMP image")); + connect(networkExportBMP, SIGNAL(triggered()), this, SLOT(slotNetworkExportBMP())); + + networkExportPNG = new QAction( QIcon(":/images/image.png"), tr("&PNG..."), this); + networkExportPNG->setStatusTip(tr("Export to PNG image")); + networkExportPNG->setWhatsThis(tr("Export PNG \n\n Exports the network to a PNG image")); + connect(networkExportPNG, SIGNAL(triggered()), this, SLOT(slotNetworkExportPNG())); + + + networkExportPDF = new QAction( QIcon(":/images/pdf.png"), tr("&PDF..."), this); + networkExportPDF->setStatusTip(tr("Export to PDF")); + networkExportPDF->setWhatsThis(tr("Export PDF\n\n Exports the network to a PDF document")); + connect(networkExportPDF, SIGNAL(triggered()), this, SLOT(slotNetworkExportPDF())); + + networkExportSM = new QAction( QIcon(":/images/save.png"), tr("&Adjacency Matrix"), this); + networkExportSM->setStatusTip(tr("Export to adjacency matrix file")); + networkExportSM->setWhatsThis(tr("Export Sociomatrix \n\n" + "Exports the network to an " + "adjacency matrix-formatted file")); + connect(networkExportSM, SIGNAL(triggered()), this, SLOT(slotNetworkExportSM())); + + networkExportPajek = new QAction( QIcon(":/images/save.png"), tr("&Pajek"), this); + networkExportPajek->setStatusTip(tr("Export to Pajek-formatted file")); + networkExportPajek->setWhatsThis(tr("Export Pajek \n\n " + "Exports the network to a Pajek-formatted file")); + connect(networkExportPajek, SIGNAL(triggered()), this, SLOT(slotNetworkExportPajek())); + + + networkExportList = new QAction( QIcon(":/images/save.png"), tr("&List"), this); + networkExportList->setStatusTip(tr("Export to List-formatted file. ")); + networkExportList->setWhatsThis(tr("Export List\n\n" + "Exports the network to a List-formatted file")); + connect(networkExportList, SIGNAL(triggered()), this, SLOT(slotNetworkExportList())); + + networkExportDL = new QAction( QIcon(":/images/save.png"), tr("&DL..."), this); + networkExportDL->setStatusTip(tr("Export to DL-formatted file")); + networkExportDL->setWhatsThis(tr("Export DL\n\n" + "Exports the active network to a DL-formatted")); + connect(networkExportDL, SIGNAL(triggered()), this, SLOT(slotNetworkExportDL())); + + networkExportGW = new QAction( QIcon(":/images/save.png"), tr("&GW..."), this); + networkExportGW->setStatusTip(tr("Export to GW-formatted file")); + networkExportGW->setWhatsThis(tr("Export\n\n" + "Exports the active network to a GW formatted file")); + connect(networkExportGW, SIGNAL(triggered()), this, SLOT(slotNetworkExportGW())); + + networkClose = new QAction( tr("&Close"), this); + networkClose->setStatusTip(tr("Close the actual network")); + networkClose->setWhatsThis(tr("Close \n\nCloses the actual network")); + connect(networkClose, SIGNAL(triggered()), this, SLOT(slotNetworkClose())); + + networkPrint = new QAction(QIcon(":/images/print.png"), tr("&Print"), this); + networkPrint->setShortcut(Qt::CTRL+Qt::Key_P); + networkPrint->setStatusTip(tr("Send the network to the printer (Ctrl+P)")); + networkPrint->setWhatsThis(tr("Printing \n\n" + "This function prints whatever is viewable on " + "the canvas. \nTo print the whole network, " + "you might want to zoom-out.")); + connect(networkPrint, SIGNAL(triggered()), this, SLOT(slotNetworkPrint())); + + networkQuit = new QAction(QIcon(":/images/exit.png"), tr("E&xit"), this); + networkQuit->setShortcut(Qt::CTRL+Qt::Key_Q); + networkQuit->setStatusTip(tr("Quits the application")); + networkQuit->setWhatsThis(tr("Exit\n\nQuits the application")); + connect(networkQuit, SIGNAL(triggered()), this, SLOT(close())); openTextEditorAct = new QAction(QIcon(":/images/texteditor.png"), tr("Open Text Editor"),this); - openTextEditorAct ->setShortcut(tr("Shift+F5")); - openTextEditorAct->setStatusTip(tr("Opens the SocNetV text editor." - "You can copy/paste network data, save and then import them...")); - openTextEditorAct->setWhatsThis(tr("Open Text Editor\n\nOpens the SocNetV text editor where you can copy paste network data, of any supported format, and save to a file. Then you can import that file to SocNetV...")); - connect(openTextEditorAct, SIGNAL(triggered()), this, SLOT(slotOpenTextEditor())); - - - viewNetworkFileAct = new QAction(QIcon(":/images/networkfile.png"), tr("View Loaded File"),this); - viewNetworkFileAct ->setShortcut(tr("F5")); - viewNetworkFileAct->setStatusTip(tr("Displays the loaded network file")); - viewNetworkFileAct->setWhatsThis(tr("View Loaded File\n\nDisplays the file of the loaded network")); - connect(viewNetworkFileAct, SIGNAL(triggered()), this, SLOT(slotViewNetworkFile())); - - viewSociomatrixAct = new QAction(QIcon(":/images/sm.png"), tr("View Adjacency Matrix"), this); - viewSociomatrixAct ->setShortcut(tr("F6")); - viewSociomatrixAct->setStatusTip(tr("Displays the adjacency matrix of the active network. See manual or online help for more...")); - viewSociomatrixAct->setWhatsThis(tr("View Adjacency Matrix\n\nDisplays the adjacency matrix of the active network. \n\n The adjacency matrix of a network is a matrix where each element a(i,j) is equal to the weight of the Edge from node i to node j. If the nodes are not connected, then a(i,j)=0. ")); - connect(viewSociomatrixAct, SIGNAL(triggered()), this, SLOT(slotViewAdjacencyMatrix())); - - - recreateDataSetAct = new QAction(QIcon(":/images/sm.png"), tr("Create Known Data Sets"), this); - recreateDataSetAct ->setShortcut(tr("F7")); - recreateDataSetAct->setStatusTip(tr("Recreates a variety of known data sets.")); - recreateDataSetAct->setWhatsThis(tr("Known Data Sets\n\nRecreates some of the most widely used data sets in network analysis studies")); - connect(recreateDataSetAct, SIGNAL(triggered()), this, SLOT(slotShowDataSetSelectDialog())); - - - - createErdosRenyiRandomNetworkAct = new QAction(QIcon(":/images/erdos.png"), tr("ErdÅ‘s–Rényi"), this); + openTextEditorAct ->setShortcut(Qt::SHIFT+Qt::Key_F5); + openTextEditorAct->setStatusTip(tr("Opens a simple text editor " + "to take notes, copy/paste network data, etc" + "(Shift+F5)")); + openTextEditorAct->setWhatsThis(tr("Open Text Editor\n\n" + "Opens the SocNetV text editor where you can " + "copy paste network data, of any supported format, " + "and save to a file. Then you can import that file to SocNetV...")); + connect(openTextEditorAct, SIGNAL(triggered()), this, SLOT(slotNetworkTextEditor())); + + + networkViewFileAct = new QAction(QIcon(":/images/networkfile.png"), + tr("View Loaded File"),this); + networkViewFileAct ->setShortcut(Qt::Key_F5); + networkViewFileAct->setStatusTip(tr("Displays the loaded network file (F5)")); + networkViewFileAct->setWhatsThis(tr("View Loaded File\n\n" + "Displays the file of the loaded network")); + connect(networkViewFileAct, SIGNAL(triggered()), this, SLOT(slotNetworkFileView())); + + networkViewSociomatrixAct = new QAction(QIcon(":/images/sm.png"), + tr("View Adjacency Matrix"), this); + networkViewSociomatrixAct ->setShortcut(Qt::Key_F6); + networkViewSociomatrixAct->setStatusTip(tr("Display the adjacency matrix of the network. " + "(F6)")); + networkViewSociomatrixAct->setWhatsThis(tr("View Adjacency Matrix\n\n" + "Displays the adjacency matrix of the active network. \n\n" + "The adjacency matrix of a network is a matrix " + "where each element a(i,j) is equal to the weight " + "of the arc from node i to node j. " + "If the nodes are not connected, then a(i,j)=0. ")); + connect(networkViewSociomatrixAct, SIGNAL(triggered()), + this, SLOT(slotNetworkViewSociomatrix())); + + networkDataSetSelectAct = new QAction(QIcon(":/images/sm.png"), + tr("Create Known Data Sets"), this); + networkDataSetSelectAct ->setShortcut(Qt::Key_F7); + networkDataSetSelectAct->setStatusTip(tr("Recreate a variety of known data sets.")); + networkDataSetSelectAct->setWhatsThis(tr("Known Data Sets\n\n" + "Recreates some of the most widely used " + "data sets in network analysis studies, i.e. " + "Krackhardt's high-tech managers")); + connect(networkDataSetSelectAct, SIGNAL(triggered()), + this, SLOT(slotNetworkDataSetSelect())); + + + createErdosRenyiRandomNetworkAct = new QAction(QIcon(":/images/erdos.png"), + tr("ErdÅ‘s–Rényi"), this); createErdosRenyiRandomNetworkAct -> setShortcut( QKeySequence(Qt::CTRL + Qt::Key_R, Qt::CTRL + Qt::Key_E) ); - createErdosRenyiRandomNetworkAct->setStatusTip(tr("Creates a random network according to the ErdÅ‘s–Rényi model")); + createErdosRenyiRandomNetworkAct->setStatusTip(tr("Creates a random network " + "according to the ErdÅ‘s–Rényi model")); createErdosRenyiRandomNetworkAct->setWhatsThis( - tr("ErdÅ‘s–Rényi \n\n") + - tr("Creates a random network either of G(n, p) model or G(n,M) model.\n") + - tr("In the first, edges are created with Bernoulli trials (probability p).\n") + - tr("In the second, a graph of exactly M edges is created.")); - connect(createErdosRenyiRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotCreateRandomErdosRenyi())); - - createLatticeNetworkAct = new QAction( QIcon(":/images/net1.png"), tr("Ring Lattice"), this); + tr("ErdÅ‘s–Rényi \n\n" + "Creates a random network either of G(n, p) model or G(n,M) model.\n" + "In the first, edges are created with Bernoulli trials (probability p).\n" + "In the second, a graph of exactly M edges is created.")); + connect(createErdosRenyiRandomNetworkAct, SIGNAL(triggered()), + this, SLOT(slotRandomErdosRenyiDialog())); + + createLatticeNetworkAct = new QAction( QIcon(":/images/net1.png"), + tr("Ring Lattice"), this); createLatticeNetworkAct -> setShortcut( QKeySequence(Qt::CTRL + Qt::Key_R, Qt::CTRL + Qt::Key_L) ); - createLatticeNetworkAct->setStatusTip(tr("Creates a ring lattice random network")); + createLatticeNetworkAct->setStatusTip(tr("Create a ring lattice random network")); createLatticeNetworkAct->setWhatsThis( tr("Ring Lattice \n\n")+ tr("A ring lattice is a graph with N nodes each connected to d neighbors, d / 2 on each side.")); - connect(createLatticeNetworkAct, SIGNAL(triggered()), this, SLOT(slotCreateRandomRingLattice())); + connect(createLatticeNetworkAct, SIGNAL(triggered()), this, SLOT(slotRandomRingLattice())); createRegularRandomNetworkAct = new QAction(QIcon(":/images/net.png"), tr("d-Regular"), this); createRegularRandomNetworkAct -> setShortcut( QKeySequence(Qt::CTRL + Qt::Key_R, Qt::CTRL + Qt::Key_R) ); - createRegularRandomNetworkAct->setStatusTip(tr("Creates a random network where every node has the same degree d.")); + createRegularRandomNetworkAct->setStatusTip(tr("Create a random network where every node has the same degree d.")); createRegularRandomNetworkAct->setWhatsThis( tr("d-Regular \n\n") + tr("Creates a random network where each node have the same number of neighbours, aka the same degree d ")); - connect(createRegularRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotCreateRegularRandomNetwork())); + connect(createRegularRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotRandomRegularNetwork())); createGaussianRandomNetworkAct = new QAction(tr("Gaussian"), this); createGaussianRandomNetworkAct -> setShortcut( QKeySequence(Qt::CTRL + Qt::Key_R, Qt::CTRL + Qt::Key_G) ); - createGaussianRandomNetworkAct->setStatusTip(tr("Creates a Gaussian distributed random network")); + createGaussianRandomNetworkAct->setStatusTip(tr("Create a Gaussian distributed random network")); createGaussianRandomNetworkAct->setWhatsThis(tr("Gaussian \n\nCreates a random network of Gaussian distribution")); - connect(createGaussianRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotCreateRandomGaussian())); + connect(createGaussianRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotRandomGaussian())); createSmallWorldRandomNetworkAct = new QAction(QIcon(":/images/sw.png"), tr("Small World"), this); createSmallWorldRandomNetworkAct-> setShortcut( QKeySequence(Qt::CTRL + Qt::Key_R, Qt::CTRL + Qt::Key_W) ); - createSmallWorldRandomNetworkAct->setStatusTip(tr("Creates a random network with small world properties")); + createSmallWorldRandomNetworkAct->setStatusTip(tr("Create a random network with small world properties")); createSmallWorldRandomNetworkAct -> setWhatsThis( tr("Small World \n\n") + tr("A Small World, according to the Watts and Strogatz model, " "is a random network with short average path lengths and high clustering coefficient.")); - connect(createSmallWorldRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotCreateRandomSmallWorld())); + connect(createSmallWorldRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotRandomSmallWorldDialog())); createScaleFreeRandomNetworkAct = new QAction( QIcon(":/images/scalefree.png"), tr("Scale-free"), this); @@ -589,121 +720,297 @@ void MainWindow::initActions(){ QKeySequence(Qt::CTRL + Qt::Key_R, Qt::CTRL + Qt::Key_S) ); createScaleFreeRandomNetworkAct->setStatusTip( - tr("Creates a random network with power-law degree distribution.")); + tr("Create a random network with power-law degree distribution.")); createScaleFreeRandomNetworkAct-> setWhatsThis( tr("Scale-free (power-law)\n\n") + tr("A scale-free network is a network whose degree distribution follows a power law." " This method generates random scale-free networks according to the " " Barabási–Albert (BA) model using a preferential attachment mechanism.")); - connect(createScaleFreeRandomNetworkAct, SIGNAL(triggered()), this, SLOT(slotCreateRandomScaleFree())); + connect(createScaleFreeRandomNetworkAct, SIGNAL(triggered()), + this, SLOT(slotRandomScaleFreeDialog())); - webCrawlerAct = new QAction(QIcon(":/images/webcrawler.png"), tr("Web Crawler"), this); - webCrawlerAct->setShortcut(tr("Shift+C")); + webCrawlerAct = new QAction(QIcon(":/images/spider.png"), tr("Web Crawler"), this); + webCrawlerAct->setShortcut(Qt::SHIFT+Qt::Key_C); webCrawlerAct->setEnabled(true); - webCrawlerAct->setStatusTip(tr("Creates a network from all links found in a given website")); - webCrawlerAct->setWhatsThis(tr("Web Crawler \n\nA Web crawler is a built-in bot, which starts with a given URL (website or webpage) to visit. As the algorithm crawls this webpage, it identifies all the links in the page and adds them to a list of URLs (called frontier). Then, all the URLs from the frontier are recursively visited. You must provide maximum recursion level (how many URLs from the frontier will be visited) and maximum running time, along with the initial web address...")); - connect(webCrawlerAct, SIGNAL(triggered()), this, SLOT(slotShowWebCrawlerDialog())); + webCrawlerAct->setStatusTip(tr("Create a network from all links found in a given website" + "Shift+C")); + webCrawlerAct->setWhatsThis(tr("Web Crawler \n\n" + "A Web crawler is a built-in bot, which " + "starts with a given URL (website or webpage) " + "to visit. As the algorithm crawls this webpage, " + "it identifies all the links in the page and adds " + "them to a list of URLs (called frontier). " + "Then, all the URLs from the frontier are " + "recursively visited. You must provide maximum " + "recursion level (how many URLs from the frontier " + "will be visited) and maximum running time, along " + "with the initial web address...")); + connect(webCrawlerAct, SIGNAL(triggered()), this, SLOT(slotNetworkWebCrawlerDialog())); /** Edit menu actions */ - selectAllAct = new QAction(QIcon(":/images/selectall.png"), tr("Select All"), this); - selectAllAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_A)); - selectAllAct->setStatusTip(tr("Selects all nodes")); - selectAllAct->setWhatsThis(tr("Select All\n\nSelects all nodes in the network")); - connect(selectAllAct, SIGNAL(triggered()), this, SLOT(slotSelectAll())); - - selectNoneAct = new QAction(QIcon(":/images/selectnone.png"), tr("Deselect all"), this); - selectNoneAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_A)); - selectNoneAct->setStatusTip(tr("Deselects all nodes")); - selectNoneAct->setWhatsThis(tr("Deselect all\n\n Clears the node selection")); - connect(selectNoneAct, SIGNAL(triggered()), this, SLOT(slotSelectNone())); - - - findNodeAct = new QAction(QIcon(":/images/find.png"), tr("Find Node"), this); - findNodeAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_F)); - findNodeAct->setStatusTip(tr("Finds and highlights a node by number or label. Press Ctrl+F again to undo.")); - findNodeAct->setWhatsThis(tr("Find Node\n\nFinds a node with a given number or label and doubles its size. Ctrl+F again resizes back the node")); - connect(findNodeAct, SIGNAL(triggered()), this, SLOT(slotFindNode()) ); - - addNodeAct = new QAction(QIcon(":/images/add.png"), tr("Add Node"), this); - addNodeAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X, Qt::CTRL + Qt::Key_A)); - addNodeAct->setStatusTip(tr("Adds a node")); - addNodeAct->setWhatsThis(tr("Add Node\n\nAdds a node to the network")); - connect(addNodeAct, SIGNAL(triggered()), this, SLOT(addNode())); - - removeNodeAct = new QAction(QIcon(":/images/remove.png"),tr("Remove Node"), this); - removeNodeAct ->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X, Qt::CTRL + Qt::Key_Backspace)); + editRelationNextAct = new QAction(QIcon(":/images/nextrelation.png"), + tr("Next Relation"), this); + editRelationNextAct->setShortcut(Qt::ALT + Qt::Key_Right); + editRelationNextAct->setToolTip(tr("Goto next graph relation (ALT+Right)")); + editRelationNextAct->setStatusTip(tr("Loads the next relation of the network (if any).")); + editRelationNextAct->setWhatsThis(tr("Next Relation\n\nLoads the next relation of the network (if any)")); + + editRelationPreviousAct = new QAction(QIcon(":/images/prevrelation.png"), + tr("Previous Relation"), this); + editRelationPreviousAct->setShortcut(Qt::ALT + Qt::Key_Left); + editRelationPreviousAct->setToolTip( + tr("Goto previous graph relation (ALT+Left)")); + editRelationPreviousAct->setStatusTip( + tr("Loads the previous relation of the network (if any).")); + editRelationPreviousAct->setWhatsThis( + tr("Previous Relation\n\n" + "Loads the previous relation of the network (if any)")); + + editRelationAddAct = new QAction(QIcon(":/images/addrelation.png"), + tr("Add New Relation"), this); + editRelationAddAct->setShortcut(Qt::ALT + Qt::CTRL + Qt::Key_N); + editRelationAddAct->setToolTip( + tr("Add a new relation to the active graph (Ctrl+Shift+N)")); + editRelationAddAct->setStatusTip( + tr("Adds a new relation to the network. " + "Nodes will be preserved, edges will be removed. ")); + editRelationAddAct->setWhatsThis( + tr("Add New Relation\n\n" + "Adds a new relation to the active network. " + "Nodes will be preserved, edges will be removed. ")); + + + zoomInAct = new QAction(QIcon(":/images/zoomin.png"), tr("Zoom In"), this); + zoomInAct->setStatusTip(tr("Zoom in. Better, use the canvas button or press Ctrl++ or press Cltr and use mouse wheel.")); + zoomInAct->setToolTip(tr("Zoom in. Better, use the canvas button or (Ctrl++)")); + zoomInAct->setWhatsThis(tr("Zoom In.\n\nZooms in the actual network")); + connect(zoomInAct, SIGNAL(triggered()), graphicsWidget, SLOT( zoomIn()) ); + + zoomOutAct = new QAction(QIcon(":/images/zoomout.png"), tr("Zoom Out"), this); + zoomOutAct->setStatusTip(tr("Zoom out. Better, use the canvas button or press Ctrl+- or press Cltr and use mouse wheel.")); + zoomOutAct->setToolTip(tr("Zoom in. Better, use the canvas button or (Ctrl+-)")); + zoomOutAct->setWhatsThis(tr("Zoom Out.\n\nZooms out of the actual network")); + connect(zoomOutAct, SIGNAL(triggered()), graphicsWidget, SLOT( zoomOut()) ); + + editRotateLeftAct = new QAction(QIcon(":/images/rotateleft.png"), tr("Rotate counterclockwise"), this); + editRotateLeftAct->setToolTip(tr("Rotate counterclockwise. Better, use the canvas button or (Ctrl+Left Arrow)")); + editRotateLeftAct->setStatusTip(tr("Rotate counterclockwise. Better, use the canvas button or Ctrl+Left Arrow")); + editRotateLeftAct ->setWhatsThis(tr("Rotates the network counterclockwise (Ctrl+Left Arrow)")); + connect(editRotateLeftAct, SIGNAL(triggered()), graphicsWidget, SLOT( rotateLeft()) ); + + editRotateRightAct = new QAction(QIcon(":/images/rotateright.png"), tr("Rotate clockwise"), this); + editRotateRightAct->setStatusTip(tr("Rotate clockwise. Better, use the canvas button or (Ctrl+Right Arrow)")); + editRotateRightAct->setToolTip(tr("Rotate clockwise. Better, use the canvas button or (Ctrl+Right Arrow)")); + editRotateRightAct ->setWhatsThis(tr("Rotates the network clockwise (Ctrl+Right Arrow)")); + connect(editRotateRightAct, SIGNAL(triggered()), graphicsWidget, SLOT( rotateRight()) ); + + editResetSlidersAct = new QAction(QIcon(":/images/reset.png"), tr("Reset Zoom and Rotation"), this); + editResetSlidersAct->setStatusTip(tr("Reset zoom and rotation to zero (Ctrl+0)")); + editResetSlidersAct->setToolTip(tr("Reset zoom and rotation to zero (Ctrl+0)")); + editResetSlidersAct->setWhatsThis(tr("Reset zoom and rotation to zero (Ctrl+0)")); + connect(editResetSlidersAct, SIGNAL(triggered()), graphicsWidget, SLOT( reset()) ); + + + editNodeSelectAllAct = new QAction(QIcon(":/images/selectall.png"), tr("Select All"), this); + editNodeSelectAllAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_A)); + editNodeSelectAllAct->setStatusTip(tr("Select all nodes")); + editNodeSelectAllAct->setWhatsThis(tr("Select All\n\nSelects all nodes in the network")); + connect(editNodeSelectAllAct, SIGNAL(triggered()), this, SLOT(slotEditNodeSelectAll())); + + editNodeSelectNoneAct = new QAction(QIcon(":/images/selectnone.png"), tr("Deselect All"), this); + editNodeSelectNoneAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_A)); + editNodeSelectNoneAct->setStatusTip(tr("Deselect all nodes")); + editNodeSelectNoneAct->setWhatsThis(tr("Deselect all\n\n Clears the node selection")); + connect(editNodeSelectNoneAct, SIGNAL(triggered()), this, SLOT(slotEditNodeSelectNone())); + + editNodeFindAct = new QAction(QIcon(":/images/find.png"), tr("Find Node"), this); + editNodeFindAct->setShortcut(Qt::CTRL + Qt::Key_F); + editNodeFindAct->setStatusTip(tr("Find and highlight a node by number or label. " + "Press Ctrl+F again to undo.")); + editNodeFindAct->setWhatsThis(tr("Find Node\n\nFinds a node with a given number or label and doubles its size. Ctrl+F again resizes back the node")); + connect(editNodeFindAct, SIGNAL(triggered()), this, SLOT(slotEditNodeFind()) ); + + editNodeAddAct = new QAction(QIcon(":/images/add.png"), tr("Add Node"), this); + editNodeAddAct->setShortcut(Qt::CTRL + Qt::Key_Period); + editNodeAddAct->setStatusTip(tr("Add a new node")); + editNodeAddAct->setWhatsThis(tr("Add Node\n\n" + "Adds a new node to the active network")); + connect(editNodeAddAct, SIGNAL(triggered()), this, SLOT(slotEditNodeAdd())); + + editNodeRemoveAct = new QAction(QIcon(":/images/remove.png"),tr("Remove Node"), this); + editNodeRemoveAct ->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_Period); //Single key shortcuts with backspace or del do no work in Mac http://goo.gl/7hz7Dx - removeNodeAct->setStatusTip(tr("Removes a node")); - removeNodeAct->setWhatsThis(tr("Remove Node\n\nRemoves a node from the network")); - connect(removeNodeAct, SIGNAL(triggered()), this, SLOT(slotRemoveNode())); - - propertiesNodeAct = new QAction(QIcon(":/images/properties.png"),tr("Node Properties"), this); - propertiesNodeAct ->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X, Qt::CTRL + Qt::Key_P)); - propertiesNodeAct->setStatusTip(tr("Open node properties")); - propertiesNodeAct->setWhatsThis(tr("Node Properties\n\nOpens node properties to edit label, size, color, shape etc")); - connect(propertiesNodeAct, SIGNAL(triggered()), this, SLOT(slotChangeNodeProperties())); - - changeAllNodesSizeAct = new QAction(QIcon(":/images/resize.png"), tr("Change all Nodes Size"), this); - changeAllNodesSizeAct->setStatusTip(tr("This option lets you change the size of all nodes")); - changeAllNodesSizeAct->setWhatsThis(tr("Nodes Size\n\nThis option lets you change the size of all nodes")); - connect(changeAllNodesSizeAct, SIGNAL(triggered()), this, SLOT(slotChangeAllNodesSize()) ); - - changeAllNodesShapeAct = new QAction( tr("Change all Nodes Shape"), this); - changeAllNodesShapeAct->setStatusTip(tr("This option lets you change the shape of all nodes")); - changeAllNodesShapeAct->setWhatsThis(tr("Nodes Shape\n\nThis option lets you change the shape of all nodes")); - connect(changeAllNodesShapeAct, SIGNAL(triggered()), this, SLOT(slotChangeAllNodesShape()) ); - - changeNumbersSizeAct = new QAction( tr("Change all Numbers Size"), this); - changeNumbersSizeAct->setStatusTip(tr("It lets you change the font size of the numbers of all nodes")); - changeNumbersSizeAct->setWhatsThis(tr("Numbers Size\n\nChanges the size of the numbers of all nodes")); - connect(changeNumbersSizeAct, SIGNAL(triggered()), this, SLOT(slotChangeNumbersSize()) ); - - changeLabelsSizeAct = new QAction( tr("Change all Labels Size"), this); - changeLabelsSizeAct->setStatusTip(tr("You can change the font size of the labels of all nodes")); - changeLabelsSizeAct->setWhatsThis(tr("Labels Size\n\nChange the fontsize of the labels of all nodes")); - connect(changeLabelsSizeAct, SIGNAL(triggered()), this, SLOT(slotChangeLabelsSize()) ); - - addEdgeAct = new QAction(QIcon(":/images/plines.png"), tr("Add Edge"),this); - addEdgeAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E, Qt::CTRL + Qt::Key_A)); - addEdgeAct->setStatusTip(tr("Adds a directed edge from a node to another")); - addEdgeAct->setWhatsThis(tr("Add Edge\n\nAdds a directed edge from a node to another")); - connect(addEdgeAct, SIGNAL(triggered()), this, SLOT(slotAddEdge())); - - removeEdgeAct = new QAction(QIcon(":/images/disconnect.png"), tr("Remove"), this); - //removeEdgeAct ->setShortcut(QKeySequence(Qt::SHIFT+Qt::Key_Backspace)); - removeEdgeAct ->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E, Qt::CTRL + Qt::Key_Backspace)); - removeEdgeAct->setStatusTip(tr("Removes an Edge")); - removeEdgeAct->setWhatsThis(tr("Remove Edge\n\nRemoves an Edge from the network")); - connect(removeEdgeAct, SIGNAL(triggered()), this, SLOT(slotRemoveEdge())); - - changeEdgeLabelAct = new QAction(QIcon(":/images/letters.png"), tr("Change Label"), this); - changeEdgeLabelAct->setStatusTip(tr("Changes the Label of an Edge")); - changeEdgeLabelAct->setWhatsThis(tr("Change Label\n\nChanges the label of an Edge")); - connect(changeEdgeLabelAct, SIGNAL(triggered()), this, SLOT(slotChangeEdgeLabel())); - changeEdgeLabelAct->setEnabled(false); - - changeEdgeColorAct = new QAction(QIcon(":/images/colorize.png"),tr("Change Color"), this); - changeEdgeColorAct->setStatusTip(tr("Changes the Color of an Edge")); - changeEdgeColorAct->setWhatsThis(tr("Change Color\n\nChanges the Color of an Edge")); - connect(changeEdgeColorAct, SIGNAL(triggered()), this, SLOT(slotChangeEdgeColor())); - - changeEdgeWeightAct = new QAction(tr("Change Weight"), this); - changeEdgeWeightAct->setStatusTip(tr("Changes the Weight of an Edge")); - changeEdgeWeightAct->setWhatsThis(tr("Change Value\n\nChanges the Weight of an Edge")); - connect(changeEdgeWeightAct, SIGNAL(triggered()), this, SLOT(slotChangeEdgeWeight())); + editNodeRemoveAct->setStatusTip(tr("Remove a node")); + editNodeRemoveAct->setWhatsThis(tr("Remove Node\n\n" + "Removes an existing node from the network")); + connect(editNodeRemoveAct, SIGNAL(triggered()), this, SLOT(slotEditNodeRemove())); + + editNodePropertiesAct = new QAction(QIcon(":/images/properties.png"),tr("Selected Node Properties"), this); + editNodePropertiesAct ->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Period ); + editNodePropertiesAct->setStatusTip(tr("Change the basic properties of the selected node(s) -- " + "There must be some nodes on the canvas!")); + editNodePropertiesAct->setWhatsThis(tr("Selected Node Properties\n\n" + "If there are some nodes on the canvas, " + " opens a properties dialog to edit " + "their label, size, color, shape etc. \n" + "You must have some node selected.")); + connect(editNodePropertiesAct, SIGNAL(triggered()), this, SLOT(slotEditNodePropertiesDialog())); + + + editNodeColorAll = new QAction(QIcon(":/images/nodecolor.png"), tr("Change All Nodes Color (this session)"), this); + editNodeColorAll->setStatusTip(tr("Choose a new color for all nodes (in this session only).")); + editNodeColorAll->setWhatsThis(tr("Nodes Color\n\n" + "Changes all nodes color at once. \n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + connect(editNodeColorAll, SIGNAL(triggered()), this, SLOT(slotEditNodeColorAll()) ); + + editNodeSizeAllAct = new QAction(QIcon(":/images/resize.png"), tr("Change All Nodes Size (this session)"), this); + editNodeSizeAllAct->setStatusTip(tr("Change the size of all nodes (in this session only)")); + editNodeSizeAllAct->setWhatsThis(tr("Nodes Size\n\n" + "Click to select and apply a new size for all nodes at once. \n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + connect(editNodeSizeAllAct, SIGNAL(triggered()), this, SLOT(slotEditNodeSizeAll()) ); + + editNodeShapeAll = new QAction( tr("Change All Nodes Shape (this session)"), this); + editNodeShapeAll->setStatusTip(tr("Change the shape of all nodes (this session only)")); + editNodeShapeAll->setWhatsThis(tr("Nodes Shape\n\n" + "Click to select and apply a new shape for all nodes at once." + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + connect(editNodeShapeAll, SIGNAL(triggered()), this, SLOT(slotEditNodeShape()) ); + + + editNodeNumbersSizeAct = new QAction( tr("Change All Node Numbers Size (this session)"), this); + editNodeNumbersSizeAct->setStatusTip(tr("Change the font size of the numbers of all nodes" + "(in this session only)")); + editNodeNumbersSizeAct->setWhatsThis(tr("Node Numbers Size\n\n" + "Click to select and apply a new font size for all node numbers" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + connect(editNodeNumbersSizeAct, SIGNAL(triggered()), + this, SLOT( slotEditNodeNumberSize( )) ); + + + editNodeNumbersColorAct = new QAction( tr("Change All Node Numbers Color (this session)"), this); + editNodeNumbersColorAct->setStatusTip(tr("Change the color of the numbers of all nodes." + "(in this session only)")); + editNodeNumbersColorAct->setWhatsThis(tr("Node Numbers Color\n\n" + "Click to select and apply a new color " + "to all node numbers." + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + connect(editNodeNumbersColorAct, SIGNAL(triggered()), this, SLOT(slotEditNodeNumbersColor())); + + editNodeLabelsSizeAct = new QAction( tr("Change All Node Labels Size (this session)"), this); + editNodeLabelsSizeAct->setStatusTip(tr("Change the font size of the labels of all nodes" + "(this session only)")); + editNodeLabelsSizeAct->setWhatsThis(tr("Node Labels Size\n\n" + "Click to select and apply a new font-size to all node labels" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + connect(editNodeLabelsSizeAct, SIGNAL(triggered()), this, SLOT(slotEditNodeLabelSize()) ); + + editNodeLabelsColorAct = new QAction( tr("Change All Node Labels Color (this session)"), this); + editNodeLabelsColorAct->setStatusTip(tr("Change the color of the labels of all nodes " + "(for this session only)")); + editNodeLabelsColorAct->setWhatsThis(tr("Labels Color\n\n" + "Click to select and apply a new color to all node labels." + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + connect(editNodeLabelsColorAct, SIGNAL(triggered()), this, SLOT(slotEditNodeLabelsColor())); + + editEdgeAddAct = new QAction(QIcon(":/images/plines.png"), tr("Add Edge (arc)"),this); + editEdgeAddAct->setShortcut(Qt::CTRL + Qt::Key_Slash); + editEdgeAddAct->setStatusTip(tr("Add a directed edge (arc) from a node to another")); + editEdgeAddAct->setWhatsThis(tr("Add Edge\n\nAdds a directed edge (arc) from a node to another")); + connect(editEdgeAddAct, SIGNAL(triggered()), this, SLOT(slotEditEdgeAdd())); + + editEdgeRemoveAct = new QAction(QIcon(":/images/disconnect.png"), tr("Remove Edge"), this); + editEdgeRemoveAct ->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_Slash); + editEdgeRemoveAct->setStatusTip(tr("Remove an Edge")); + editEdgeRemoveAct->setWhatsThis(tr("Remove Edge\n\n" + "Removes an Edge from the network." + "If an edge has been clicked previously " + "it is removed. " + "Otherwise, it asks for source and target " + "nodes")); + connect(editEdgeRemoveAct, SIGNAL(triggered()), this, SLOT(slotEditEdgeRemove())); + + editEdgeLabelAct = new QAction(QIcon(":/images/letters.png"), tr("Change Edge Label"), this); + editEdgeLabelAct->setStatusTip(tr("Change the Label of an Edge")); + editEdgeLabelAct->setWhatsThis(tr("Change Edge Label\n\n" + "Changes the label of an Edge")); + connect(editEdgeLabelAct, SIGNAL(triggered()), this, SLOT(slotEditEdgeLabel())); + + + editEdgeColorAct = new QAction(QIcon(":/images/colorize.png"),tr("Change Edge Color"), this); + editEdgeColorAct->setStatusTip(tr("Change the Color of an Edge")); + editEdgeColorAct->setWhatsThis(tr("Change Edge Color\n\n" + "Changes the Color of an Edge")); + connect(editEdgeColorAct, SIGNAL(triggered()), this, SLOT(slotEditEdgeColor())); + + editEdgeWeightAct = new QAction(QIcon(":/images/edgeweight.png") ,tr("Change Edge Weight"), this); + editEdgeWeightAct->setStatusTip(tr("Change the weight of an Edge")); + editEdgeWeightAct->setWhatsThis(tr("Edge Weight\n\n" + "Changes the Weight of an Edge")); + connect(editEdgeWeightAct, SIGNAL(triggered()), this, SLOT(slotEditEdgeWeight())); + + editEdgeColorAllAct = new QAction( tr("Change All Edges Color"), this); + editEdgeColorAllAct->setStatusTip(tr("Change the color of all Edges.")); + editEdgeColorAllAct->setWhatsThis(tr("All Edges Color\n\n" + "Changes the color of all Edges")); + connect(editEdgeColorAllAct, SIGNAL(triggered()), this, SLOT(slotEditEdgeColorAll())); + + editEdgeSymmetrizeAllAct= new QAction(QIcon(":/images/symmetrize.png"), tr("Symmetrize Edges"), this); + editEdgeSymmetrizeAllAct ->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E, Qt::CTRL + Qt::Key_S)); + editEdgeSymmetrizeAllAct->setStatusTip(tr("Make all arcs reciprocal (thus, a symmetric graph).")); + editEdgeSymmetrizeAllAct->setWhatsThis( + tr("Symmetrize Edges\n\n" + "Makes all directed arcs reciprocal. \n" + "If there is an arc from node A to node B \n" + "then a new arc from node B to node A is created \n" + "with the same weight" + "The result is a symmetric network")); + connect(editEdgeSymmetrizeAllAct, SIGNAL(triggered()), this, SLOT(slotEditEdgeSymmetrizeAll())); + + editEdgeUndirectedAllAct= new QAction( tr("Undirected Edges"), this); + editEdgeUndirectedAllAct ->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E, Qt::CTRL + Qt::Key_U)); + editEdgeUndirectedAllAct->setStatusTip(tr("Tranform all arcs to undirected edges (thus, an undirected graph).")); + editEdgeUndirectedAllAct->setWhatsThis( + tr("Undirected Edges\n\n" + "Tranforms all directed arcs to undirected edges. \n" + "The result is a undirected and symmetric network")); + editEdgeUndirectedAllAct -> setCheckable(true); + editEdgeUndirectedAllAct -> setChecked(false); + connect(editEdgeUndirectedAllAct, SIGNAL(toggled(bool)), + this, SLOT(slotEditEdgeUndirectedAll(bool))); + + + transformNodes2EdgesAct = new QAction( tr("Transform Nodes to Edges"),this); + transformNodes2EdgesAct->setStatusTip(tr("Transforms the network so that " + "nodes become Edges and vice versa")); + transformNodes2EdgesAct->setWhatsThis(tr("Transform Nodes EdgesAct\n\n" + "Transforms network so that nodes become Edges and vice versa")); + connect(transformNodes2EdgesAct, SIGNAL(triggered()), + this, SLOT(slotTransformNodes2Edges())); + + filterNodesAct = new QAction(tr("Filter Nodes"), this); filterNodesAct -> setEnabled(false); //filterNodesAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X, Qt::CTRL + Qt::Key_F)); filterNodesAct->setStatusTip(tr("Filters Nodes of some value out of the network")); - filterNodesAct->setWhatsThis(tr("Filter Nodes\n\nFilters Nodes of some value out of the network.")); + filterNodesAct->setWhatsThis(tr("Filter Nodes\n\n" + "Filters Nodes of some value out of the network.")); connect(filterNodesAct, SIGNAL(triggered()), this, SLOT(slotFilterNodes())); filterIsolateNodesAct = new QAction(tr("Filter Isolate Nodes"), this); @@ -712,55 +1019,22 @@ void MainWindow::initActions(){ filterIsolateNodesAct -> setChecked(false); filterIsolateNodesAct -> setShortcut(QKeySequence(Qt::CTRL + Qt::Key_X, Qt::CTRL + Qt::Key_F)); filterIsolateNodesAct -> setStatusTip(tr("Filters nodes with no edges")); - filterIsolateNodesAct -> setWhatsThis(tr("Filter Isolate Nodes\n\n Enables or disables displaying of isolate nodes. Isolate nodes are those with no edges...")); - connect(filterIsolateNodesAct, SIGNAL(toggled(bool)), this, SLOT(slotFilterIsolateNodes(bool))); + filterIsolateNodesAct -> setWhatsThis(tr("Filter Isolate Nodes\n\n " + "Enables or disables displaying of isolate nodes. Isolate nodes are those with no edges...")); + connect(filterIsolateNodesAct, SIGNAL(toggled(bool)), + this, SLOT(slotFilterIsolateNodes(bool))); - filterEdgesAct = new QAction(tr("Filter Edges by weight"), this); + filterEdgesAct = new QAction(tr("Filter Edges by Weight"), this); filterEdgesAct -> setEnabled(true); filterEdgesAct -> setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E, Qt::CTRL + Qt::Key_F)); filterEdgesAct -> setStatusTip(tr("Filters Edges of some weight out of the network")); - filterEdgesAct -> setWhatsThis(tr("Filter Edges\n\nFilters Edge of some specific weight out of the network.")); - connect(filterEdgesAct , SIGNAL(triggered()), this, SLOT(slotShowFilterEdgesDialog())); - - changeBackColorAct = new QAction(QIcon(":/images/color.png"), tr("Change Background Color"), this); - changeBackColorAct->setStatusTip(tr("Click to change the background color")); - changeBackColorAct->setWhatsThis(tr("Background\n\nChanges background color")); - connect(changeBackColorAct, SIGNAL(triggered()), this, SLOT(slotBackgroundColor())); - - changeAllNodesColorAct = new QAction(QIcon(":/images/nodecolor.png"), tr("Change all Nodes Colors"), this); - changeAllNodesColorAct->setStatusTip(tr("Click to choose a new color for all nodes.")); - changeAllNodesColorAct->setWhatsThis(tr("All Nodes\n\nChanges all nodes color at once.")); - connect(changeAllNodesColorAct, SIGNAL(triggered()), this, SLOT(slotAllNodesColor()) ); - - changeAllNumbersColorAct = new QAction( tr("Change all Numbers Colors"), this); - changeAllNumbersColorAct->setStatusTip(tr("Click to change the color of all numbers.")); - changeAllNumbersColorAct->setWhatsThis(tr("Numbers\n\nChanges the color of all numbers.")); - connect(changeAllNumbersColorAct, SIGNAL(triggered()), this, SLOT(slotAllNumbersColor())); - - changeAllLabelsColorAct = new QAction( tr("Change all Labels Colors"), this); - changeAllLabelsColorAct->setStatusTip(tr("Click to change the color of all node labels.")); - changeAllLabelsColorAct->setWhatsThis(tr("Numbers\n\nChanges the color of all node labels.")); - connect(changeAllLabelsColorAct, SIGNAL(triggered()), this, SLOT(slotAllLabelsColor())); - - changeAllEdgesColorAct = new QAction( tr("Change all Edges Colors"), this); - changeAllEdgesColorAct->setStatusTip(tr("Click to change the color of all Edges.")); - changeAllEdgesColorAct->setWhatsThis(tr("Background\n\nChanges all Edges color")); - connect(changeAllEdgesColorAct, SIGNAL(triggered()), this, SLOT(slotAllEdgesColor())); + filterEdgesAct -> setWhatsThis(tr("Filter Edges\n\n" + "Filters Edge of some specific weight out of the network.")); + connect(filterEdgesAct , SIGNAL(triggered()), + this, SLOT(slotShowFilterEdgesDialog())); - transformNodes2EdgesAct = new QAction( tr("Transform Nodes to Edges"),this); - transformNodes2EdgesAct->setStatusTip(tr("Transforms the network so that nodes become Edges and vice versa")); - transformNodes2EdgesAct->setWhatsThis(tr("Transform Nodes EdgesAct\n\nTransforms network so that nodes become Edges and vice versa")); - connect(transformNodes2EdgesAct, SIGNAL(triggered()), this, SLOT(slotTransformNodes2Edges())); - - symmetrizeAct= new QAction(QIcon(":/images/symmetrize.png"), tr("Symmetrize Edges"), this); - symmetrizeAct ->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E, Qt::CTRL + Qt::Key_S)); - symmetrizeAct->setStatusTip(tr("Makes all edges reciprocal (thus, a symmetric graph).")); - symmetrizeAct->setWhatsThis(tr("Symmetrize Edges\n\nTransforms all directed arcs to undirected edges. The result is a symmetric network")); - connect(symmetrizeAct, SIGNAL(triggered()), this, SLOT(slotSymmetrize())); - - /** @@ -784,7 +1058,7 @@ void MainWindow::initActions(){ connect(regularColorationAct, SIGNAL(triggered() ), this, SLOT(slotColorationRegular()) );//TODO randLayoutAct = new QAction( tr("Random"),this); - randLayoutAct -> setShortcut(Qt::CTRL+Qt::Key_0); + randLayoutAct -> setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_0); randLayoutAct -> setStatusTip(tr("Repositions all nodes in random places")); randLayoutAct -> setWhatsThis(tr("Random Layout\n\n Repositions all nodes in random places")); connect(randLayoutAct, SIGNAL(triggered()), this, SLOT(slotLayoutRandom())); @@ -996,10 +1270,15 @@ void MainWindow::initActions(){ - clearGuidesAct = new QAction(QIcon(":/images/gridlines.png"), tr("Remove Layout GuideLines"), this); - clearGuidesAct ->setStatusTip(tr("Removes all layout guideLines from the canvas.")); - clearGuidesAct->setWhatsThis(tr("Remove GuideLines\n\n Removes any guidelines (circles or horizontal lines) created for the network layout.")); - + layoutGuidesAct = new QAction(QIcon(":/images/gridlines.png"), tr("Layout GuideLines"), this); + layoutGuidesAct ->setStatusTip(tr("Toggles layout guidelines on or off.")); + layoutGuidesAct->setWhatsThis(tr("Layout Guidelines\n\n" + "Layout Guidelines are circular or horizontal lines \n" + "usually created when embedding prominence-based \n" + "visualization models on the network.\n" + "Disable this checkbox to hide guidelines")); + layoutGuidesAct->setCheckable(true); + layoutGuidesAct->setChecked(true); @@ -1208,64 +1487,19 @@ void MainWindow::initActions(){ springLayoutAct= new QAction(tr("Spring Embedder (Eades)"), this); springLayoutAct->setShortcut(tr("Alt+1")); - springLayoutAct->setCheckable(true); - springLayoutAct->setChecked(false); springLayoutAct->setStatusTip(tr("All nodes repel each other while the connected ones are attracted as if connected by springs.")); springLayoutAct->setWhatsThis(tr("Spring Embedder Layout\n\n In this model, nodes are regarded as physical bodies (i.e. electrons) which exert repelling forces to each other, while edges are springs connecting adjacents nodes. Non-adjacent nodes repel each other while connected nodes are The algorithm continues until the system retains an equilibrium state in which all forces cancel each other. ")); - connect(springLayoutAct, SIGNAL(triggered(bool)), this, SLOT(slotLayoutSpringEmbedder(bool))); + connect(springLayoutAct, SIGNAL(triggered(bool)), this, SLOT(slotLayoutSpringEmbedder())); FRLayoutAct= new QAction( tr("Fruchterman-Reingold"), this); FRLayoutAct->setShortcut(tr("Alt+2")); - FRLayoutAct->setCheckable(true); - FRLayoutAct->setChecked(false); FRLayoutAct->setStatusTip(tr("Repelling forces between all nodes, and attracting forces between adjacent nodes.")); FRLayoutAct->setWhatsThis(tr("Fruchterman-Reingold Layout\n\n Embeds a layout all nodes according to a model in which repelling forces are used between every pair of nodes, while attracting forces are used only between adjacent nodes. The algorithm continues until the system retains its equilibrium state where all forces cancel each other.")); connect(FRLayoutAct, SIGNAL(triggered()), this, SLOT(slotLayoutFruchterman())); - zoomInAct = new QAction(QIcon(":/images/zoomin.png"), tr("Zoom &in"), this); - zoomInAct->setShortcut(Qt::CTRL + Qt::Key_Plus); - zoomInAct->setToolTip(tr("Zoom in (Ctrl++)")); - zoomInAct->setStatusTip(tr("Zooms inside the actual network.")); - zoomInAct->setWhatsThis(tr("Zoom In.\n\nZooms in. What else did you expect?")); - - zoomOutAct = new QAction(QIcon(":/images/zoomout.png"), tr("Zoom &out"), this); - zoomOutAct->setShortcut(Qt::CTRL + Qt::Key_Minus); - zoomOutAct->setToolTip(tr("Zoom out (Ctrl+-)")); - zoomOutAct->setStatusTip(tr("Zooms out of the actual network.")); - zoomOutAct->setWhatsThis(tr("Zoom out.\n\nZooms out. What else did you expect?")); - - - nextRelationAct = new QAction(QIcon(":/images/nextrelation.png"), - tr("Next Relation"), this); - nextRelationAct->setShortcut(Qt::CTRL + Qt::Key_Right); - nextRelationAct->setToolTip(tr("Goto next graph relation (Ctrl+Right)")); - nextRelationAct->setStatusTip(tr("Loads the next relation of the network (if any).")); - nextRelationAct->setWhatsThis(tr("Next Relation\n\nLoads the next relation of the network (if any)")); - prevRelationAct = new QAction(QIcon(":/images/prevrelation.png"), - tr("Previous Relation"), this); - prevRelationAct->setShortcut(Qt::CTRL + Qt::Key_Left); - prevRelationAct->setToolTip( - tr("Goto previous graph relation (Ctrl+Left)")); - prevRelationAct->setStatusTip( - tr("Loads the previous relation of the network (if any).")); - prevRelationAct->setWhatsThis( - tr("Previous Relation\n\n" - "Loads the previous relation of the network (if any)")); - addRelationAct = new QAction(QIcon(":/images/addrelation.png"), - tr("Add New Relation"), this); - addRelationAct->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_N); - addRelationAct->setToolTip( - tr("Add a new relation to the active graph (Ctrl+Shift+N)")); - addRelationAct->setStatusTip( - tr("Adds a new relation to the network. " - "Nodes will be preserved, edges will be removed. ")); - addRelationAct->setWhatsThis( - tr("Add New Relation\n\n" - "Adds a new relation to the active network. " - "Nodes will be preserved, edges will be removed. ")); nodeSizesByOutDegreeAct= new QAction(QIcon(":/images/nodeout.png"), tr("Node sizes by OutDegree"), this); @@ -1540,7 +1774,14 @@ void MainWindow::initActions(){ cInformationAct->setShortcut(tr("Ctrl+8")); cInformationAct->setEnabled(true); cInformationAct->setStatusTip(tr("Calculate and display Information Centrality indices and group Information Centralization")); - cInformationAct->setWhatsThis(tr("Information Centrality (IC)\n\n Information centrality counts all paths between nodes weighted by strength of tie and distance. This centrality measure developed by Stephenson and Zelen (1989) focuses on how information might flow through many different paths. \n\nThis index should be calculated only for graphs. \n\n Note: To compute this index, SocNetV drops all isolated nodes.")); + cInformationAct->setWhatsThis( + tr("Information Centrality (IC)\n\n " + "Information centrality counts all paths between " + "nodes weighted by strength of tie and distance. " + "This centrality measure developed by Stephenson and Zelen (1989) " + "focuses on how information might flow through many different paths. \n\n" + "This index should be calculated only for graphs. \n\n " + "Note: To compute this index, SocNetV drops all isolated nodes.")); connect(cInformationAct, SIGNAL(triggered()), this, SLOT(slotCentralityInformation())); cInDegreeAct = new QAction(tr("Degree Prestige (DP)"), this); @@ -1580,137 +1821,200 @@ void MainWindow::initActions(){ "where the sum is over all nodes in I.")); connect(cProximityPrestigeAct, SIGNAL(triggered()), this, SLOT(slotPrestigeProximity())); + /** Options menu actions */ - displayNodeNumbersAct = new QAction( tr("Display Numbers"), this ); - displayNodeNumbersAct->setStatusTip(tr("Toggles displaying of node numbers")); - displayNodeNumbersAct->setWhatsThis(tr("Display Numbers\n\nEnables/disables node numbers")); - displayNodeNumbersAct->setCheckable (true); - displayNodeNumbersAct->setChecked(true); - connect(displayNodeNumbersAct, SIGNAL(toggled(bool)), this, SLOT(slotDisplayNodeNumbers(bool))); - - displayNodeLabelsAct= new QAction(tr("Display Labels"), this ); - displayNodeLabelsAct->setStatusTip(tr("Toggles displaying of node labels")); - displayNodeLabelsAct->setWhatsThis(tr("Display Labels\n\nEnables/disables node labels")); - displayNodeLabelsAct->setCheckable (true); - displayNodeLabelsAct->setChecked(false); - connect(displayNodeLabelsAct, SIGNAL(toggled(bool)), this, SLOT(slotDisplayNodeLabels(bool))); - - - displayNumbersInsideNodesAct= new QAction(tr("Display Numbers Inside Nodes"), this ); - displayNumbersInsideNodesAct->setStatusTip(tr("Toggles displaying numbers inside nodes")); - displayNumbersInsideNodesAct->setWhatsThis(tr("Display Numbers Inside Nodes\n\nTurns on/off displaying nodenumbers inside nodes")); - displayNumbersInsideNodesAct->setCheckable (true); - displayNumbersInsideNodesAct->setChecked(false); - connect(displayNumbersInsideNodesAct, SIGNAL(toggled(bool)), this, SLOT(slotDisplayNumbersInsideNodes(bool))); - - - displayEdgesAct = new QAction(tr("Display Edges"), this); - displayEdgesAct->setStatusTip(tr("Toggle to display or not Edges")); - displayEdgesAct->setWhatsThis(tr("Display Edges\n\nClick to enable or disable displaying of Edges")); - displayEdgesAct->setCheckable(true); - displayEdgesAct->setChecked(true); - connect(displayEdgesAct, SIGNAL(toggled(bool)), this, SLOT(slotDisplayEdges(bool)) ); - - displayEdgesWeightNumbersAct = new QAction(tr("Display Edge Weights"), this); - displayEdgesWeightNumbersAct->setStatusTip(tr("Toggles displaying of numbers of Edges weights")); - displayEdgesWeightNumbersAct->setWhatsThis(tr("Display Weight Numbers\n\nClick to enable or disable displaying numbers of Edges weight")); - displayEdgesWeightNumbersAct->setCheckable(true); - displayEdgesWeightNumbersAct->setChecked(false); - connect(displayEdgesWeightNumbersAct, SIGNAL(toggled(bool)), - this, SLOT(slotDisplayEdgesWeightNumbers(bool)) ); - - considerEdgeWeightsAct = new QAction(tr("Consider Weights in calculcations"), this); + optionsNodeNumbersVisibilityAct = new QAction( tr("Display Node Numbers"), this ); + optionsNodeNumbersVisibilityAct->setStatusTip( + tr("Toggle displaying of node numbers (this session only)")); + optionsNodeNumbersVisibilityAct->setWhatsThis( + tr("Display Node Numbers\n\n" + "Enables or disables displaying of node numbers\n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + optionsNodeNumbersVisibilityAct->setCheckable (true); + optionsNodeNumbersVisibilityAct->setChecked ( + ( appSettings["initNodeNumbersVisibility"] == "true" ) ? true: false ); + connect(optionsNodeNumbersVisibilityAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsNodeNumbersVisibility(bool))); + + + optionsNodeNumbersInsideAct = new QAction(tr("Display Numbers Inside Nodes"), this ); + optionsNodeNumbersInsideAct->setStatusTip( + tr("Toggle displaying of numbers inside nodes (this session only)")); + optionsNodeNumbersInsideAct->setWhatsThis( + tr("Display Numbers Inside Nodes\n\n" + "Enables or disables displaying node numbers inside nodes.\n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + optionsNodeNumbersInsideAct->setCheckable (true); + optionsNodeNumbersInsideAct->setChecked( + ( appSettings["initNodeNumbersInside"] == "true" ) ? true: false ); + connect(optionsNodeNumbersInsideAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsNodeNumbersInside(bool))); + + + optionsNodeLabelsVisibilityAct= new QAction(tr("Display Node Labels"), this ); + optionsNodeLabelsVisibilityAct->setStatusTip( + tr("Toggle displaying of node labels (this session only)")); + optionsNodeLabelsVisibilityAct->setWhatsThis( + tr("Display Node Labels\n\n" + "Enables or disables node labels.\n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + optionsNodeLabelsVisibilityAct->setCheckable (true); + optionsNodeLabelsVisibilityAct->setChecked( + ( appSettings["initNodeLabelsVisibility"] == "true" ) ? true: false ); + connect(optionsNodeLabelsVisibilityAct, SIGNAL(toggled(bool)), + this, SLOT(slotOptionsNodeLabelsVisibility(bool))); + + + optionsEdgesVisibilityAct = new QAction(tr("Display Edges"), this); + optionsEdgesVisibilityAct->setStatusTip(tr("Toggle displaying edges (this session only)")); + optionsEdgesVisibilityAct->setWhatsThis( + tr("Display Edges\n\n" + "Enables or disables displaying of edges" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + optionsEdgesVisibilityAct->setCheckable(true); + optionsEdgesVisibilityAct->setChecked( + (appSettings["initEdgesVisibility"] == "true") ? true: false + ); + connect(optionsEdgesVisibilityAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsEdgesVisibility(bool)) ); + + + optionsEdgeWeightNumbersAct = new QAction(tr("Display Edge Weights"), this); + optionsEdgeWeightNumbersAct->setStatusTip( + tr("Toggle displaying of numbers of Edges weights (this session only)")); + optionsEdgeWeightNumbersAct->setWhatsThis( + tr("Display Edge Weights\n\n" + "Enables or disables displaying edge weight numbers.\n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + optionsEdgeWeightNumbersAct->setCheckable(true); + optionsEdgeWeightNumbersAct->setChecked( + (appSettings["initEdgeWeightNumbersVisibility"] == "true") ? true: false + ); + connect(optionsEdgeWeightNumbersAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsEdgeWeightNumbersVisibility(bool)) ); + + considerEdgeWeightsAct = new QAction(tr("Consider edge Weights in calculations"), this); considerEdgeWeightsAct-> setStatusTip( - tr("Toggles considering Edge weights during calculations (i.e. distances, centrality, etc)")); + tr("Toggle considering edge Weights during calculations " + "(i.e. distances, centrality, etc) (this session only)")); considerEdgeWeightsAct-> setWhatsThis( - tr("Display Weight Numbers\n\n" - "Click to enable or disable considering edge weights during " - "calculations (i.e. distances, centrality, etc)")); + tr("Consider edge weights in calculations\n\n" + "Enables or disables considering edge weights during " + "calculations (i.e. distances, centrality, etc).\n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); considerEdgeWeightsAct->setCheckable(true); considerEdgeWeightsAct->setChecked(false); connect(considerEdgeWeightsAct, SIGNAL(triggered(bool)), - this, SLOT(slotConsiderEdgeWeights(bool)) ); - - displayEdgesArrowsAct = new QAction( tr("Display Arrows"),this); - displayEdgesArrowsAct->setStatusTip(tr("Toggles displaying of arrows on edges")); - displayEdgesArrowsAct->setWhatsThis(tr("Display Arrows\n\nClick to enable or disable displaying of arrows on edges")); - displayEdgesArrowsAct->setCheckable(true); - displayEdgesArrowsAct->setChecked(true); - connect(displayEdgesArrowsAct, SIGNAL(toggled(bool)), this, SLOT(slotDisplayEdgesArrows(bool)) ); - - drawEdgesWeightsAct = new QAction( tr("Thickness=Weight"), this); - drawEdgesWeightsAct->setStatusTip(tr("Draws edges as thick as their weights (if specified)")); - drawEdgesWeightsAct->setWhatsThis(tr("Draw As Thick As Weights\n\nClick to toggle having all edges as thick as their weight (if specified)")); - drawEdgesWeightsAct->setCheckable(true); - drawEdgesWeightsAct->setChecked(false); - drawEdgesWeightsAct->setEnabled(false); - connect(drawEdgesWeightsAct, SIGNAL(toggled(bool)), this, SLOT(slotDrawEdgesThickAsWeights()) ); + this, SLOT(slotOptionsEdgeWeightsDuringComputation(bool)) ); + + + optionsEdgeLabelsAct = new QAction(tr("Display Edge Labels"), this); + optionsEdgeLabelsAct->setStatusTip( + tr("Toggle displaying of Edge labels, if any (this session only)")); + optionsEdgeLabelsAct->setWhatsThis( + tr("Display Edge Labes\n\n" + "Enables or disables displaying edge labels.\n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + optionsEdgeLabelsAct->setCheckable(true); + optionsEdgeLabelsAct->setChecked( + (appSettings["initEdgeLabelsVisibility"] == "true") ? true: false + ); + connect(optionsEdgeLabelsAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsEdgeLabelsVisibility(bool)) ); + + + optionsEdgeArrowsAct = new QAction( tr("Display Edge Arrows"),this); + optionsEdgeArrowsAct->setStatusTip( + tr("Toggle displaying directional Arrows on edges (this session only)")); + optionsEdgeArrowsAct->setWhatsThis( + tr("Display edge Arrows\n\n" + "Enables or disables displaying of arrows on edges.\n " + "Useful if all links are reciprocal (undirected graph).\n" + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); + optionsEdgeArrowsAct->setCheckable(true); + optionsEdgeArrowsAct->setChecked( + (appSettings["initEdgeArrows"]=="true") ? true: false + ); + connect(optionsEdgeArrowsAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsEdgeArrowsVisibility(bool)) ); + + optionsEdgeThicknessPerWeightAct = new QAction( tr("Edge Thickness reflects Weight"), this); + optionsEdgeThicknessPerWeightAct->setStatusTip(tr("Draw edges as thick as their weights (if specified)")); + optionsEdgeThicknessPerWeightAct->setWhatsThis( + tr("Edge thickness reflects weight\n\n" + "Click to toggle having all edges as thick as their weight (if specified)")); + optionsEdgeThicknessPerWeightAct->setCheckable(true); + optionsEdgeThicknessPerWeightAct->setChecked( + (appSettings["initEdgeThicknessPerWeight"]=="true") ? true: false + ); + connect(optionsEdgeThicknessPerWeightAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsEdgeThicknessPerWeight()) ); + optionsEdgeThicknessPerWeightAct->setEnabled(false); drawEdgesBezier = new QAction( tr("Bezier Curves"), this); - drawEdgesBezier->setStatusTip(tr("Draws Edges as Bezier curves")); - drawEdgesBezier->setWhatsThis(tr("Edges Bezier\n\nEnables/Disables drawing Edges as Bezier curves.")); + drawEdgesBezier->setStatusTip(tr("Draw Edges as Bezier curves")); + drawEdgesBezier->setWhatsThis( + tr("Edges Bezier\n\n" + "Enable or disables drawing Edges as Bezier curves." + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); drawEdgesBezier->setCheckable(true); - drawEdgesBezier->setChecked (false); + drawEdgesBezier->setChecked ( + (appSettings["initEdgeShape"]=="bezier") ? true: false + ); drawEdgesBezier->setEnabled(false); - connect(drawEdgesBezier, SIGNAL(toggled(bool)), this, SLOT(slotDrawEdgesBezier(bool)) ); + connect(drawEdgesBezier, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsEdgesBezier(bool)) ); - /** - Options > View menu actions - */ - - antialiasingAct = new QAction(tr("Anti-Aliasing"), this); - antialiasingAct ->setShortcut(tr("F8")); - antialiasingAct ->setStatusTip(tr("Enables/disables anti-aliasing")); - antialiasingAct ->setWhatsThis(tr("Enable or disable Anti-Aliasing\n\n Anti-aliasing is a technique which makes nodes, lines and text, smoother and fancier. But it comes at the cost of speed...")); - antialiasingAct ->setCheckable(true); - antialiasingAct ->setChecked (true); - connect(antialiasingAct , SIGNAL(toggled(bool)), this, SLOT(slotAntialiasing(bool))); - - - showProgressBarAct = new QAction(tr("Progress Bars"), this); - showProgressBarAct ->setShortcut(tr("F10")); - showProgressBarAct->setStatusTip(tr("Enables/disables Progress Bars")); - showProgressBarAct->setWhatsThis(tr("Enable or disable Progress Bars\n\nProgress Bars may appear during time-cost operations. Enabling progressBar has a significant cpu cost but lets you know about the progress of a given operation.")); - showProgressBarAct->setCheckable(true); - showProgressBarAct->setChecked (true); - connect(showProgressBarAct, SIGNAL(toggled(bool)), this, SLOT(slotShowProgressBar(bool))); - - printDebugAct = new QAction(tr("Debug Messages"), this); - printDebugAct ->setShortcut(tr("F9")); - printDebugAct->setStatusTip(tr("Enables/disables printing debug messages to stdout")); - printDebugAct->setWhatsThis(tr("Enables or disable Debug Messages\n\nPrinting debug messages to strerr. Enabling has a significant cpu cost but lets you know what SocNetV is actually doing.")); - printDebugAct->setCheckable(true); - printDebugAct->setChecked (false); - printDebug=false; - connect(printDebugAct, SIGNAL(toggled(bool)), this, SLOT(slotPrintDebug(bool))); - - - - viewToolBar = new QAction(tr("Toolbar"), this); - viewToolBar->setStatusTip(tr("Enables/disables the toolbar")); - viewToolBar->setWhatsThis(tr("Enable or disable Toolbar\n\nThe toolbar is the widget right below the menu, and carries useful icons. You can disable it if you like...")); - viewToolBar->setCheckable(true); - viewToolBar->setChecked(true); - connect(viewToolBar, SIGNAL(toggled(bool)), this, SLOT(slotViewToolBar(bool))); - - viewStatusBar = new QAction(tr("Statusbar"), this); - viewStatusBar->setStatusTip(tr("Enables/disables the statusbar")); - viewStatusBar->setWhatsThis(tr("Enable or disable Statusbar\n\nThe statusbar is the widget at the bottom of the window, where messages appear. You might want to disable it...")); - viewStatusBar->setCheckable(true); - viewStatusBar->setChecked(true); - connect(viewStatusBar, SIGNAL(toggled(bool)), this, SLOT(slotViewStatusBar(bool))); - - backgroundImageAct = new QAction(tr("Background Image"), this); - backgroundImageAct->setStatusTip(tr("Enables/disables displaying a user-defined custom image in the background")); - backgroundImageAct->setWhatsThis(tr("Enable or disable background image\n\n If you enable it, you will be asked for a image file, which will be displayed in the background instead of plain color..")); + changeBackColorAct = new QAction(QIcon(":/images/color.png"), tr("Change Background Color"), this); + changeBackColorAct->setStatusTip(tr("Change the canvasbackground color")); + changeBackColorAct->setWhatsThis(tr("Background Color\n\n" + "Changes the background color of the canvas")); + connect(changeBackColorAct, SIGNAL(triggered()), + this, SLOT(slotOptionsBackgroundColor())); + + + backgroundImageAct = new QAction(tr("Background Image (this session)"), this); + backgroundImageAct->setStatusTip( + tr("Select and display a custom image in the background" + "(for this session only)")); + backgroundImageAct->setWhatsThis( + tr("Background image\n\n " + "Enable to select an image file from your computer, " + "which will be displayed in the background instead of plain color." + "This setting will apply to this session only. \n" + "To permanently change it, use Settings & Preferences")); backgroundImageAct->setCheckable(true); backgroundImageAct->setChecked(false); - connect(backgroundImageAct, SIGNAL(toggled(bool)), this, SLOT(slotBackgroundImage(bool))); + connect(backgroundImageAct, SIGNAL(triggered(bool)), + this, SLOT(slotOptionsBackgroundImageSelect(bool))); + + openSettingsAct = new QAction(QIcon(":/images/appsettings.png"), tr("Settings"), this); + openSettingsAct->setShortcut(Qt::CTRL + Qt::Key_Comma); + openSettingsAct->setEnabled(true); + openSettingsAct->setStatusTip( + tr("Open Settings dialog where you can save your preferences " + "for all future sessions")); + openSettingsAct->setWhatsThis( + tr("Settings\n\n " + "Opens the Settings dialog where you can edit and save settings " + "permanently for all subsequent sessions.")); + connect(openSettingsAct, SIGNAL(triggered()), + this, SLOT(slotOpenSettingsDialog())); + @@ -1723,10 +2027,21 @@ void MainWindow::initActions(){ helpApp->setWhatsThis(tr("Manual\n\nDisplays the documentation of SocNetV")); connect(helpApp, SIGNAL(triggered()), this, SLOT(slotHelp())); - tipsApp = new QAction(tr("Tip of the Day"), this); + tipsApp = new QAction(QIcon(":/images/help-hint.png"), tr("Tip of the Day"), this); tipsApp->setStatusTip(tr("Read useful tips")); tipsApp->setWhatsThis(tr("Quick Tips\n\nDisplays some useful and quick tips")); - connect(tipsApp, SIGNAL(triggered()), this, SLOT(slotTips())); + connect(tipsApp, SIGNAL(triggered()), this, SLOT(slotHelpTips())); + + + helpCheckUpdatesApp = new QAction( + QIcon(":/images/download.png"), tr("Check for Updates"), this); + helpCheckUpdatesApp->setStatusTip(tr("Open a browser to SocNetV website " + "to check for a new version...")); + helpCheckUpdatesApp->setWhatsThis(tr("Check Updates\n\n" + "Open a browser to SocNetV website so " + "that you can check yourself for updates")); + connect(helpCheckUpdatesApp, SIGNAL(triggered()), + this, SLOT(slotHelpCheckUpdates())); helpAboutApp = new QAction(tr("About SocNetV"), this); helpAboutApp->setStatusTip(tr("About SocNetV")); @@ -1735,7 +2050,7 @@ void MainWindow::initActions(){ - helpAboutQt = new QAction(tr("About Qt"), this); + helpAboutQt = new QAction(QIcon(":/images/qt.png"), tr("About Qt"), this); helpAboutQt->setStatusTip(tr("About Qt")); helpAboutQt->setWhatsThis(tr("About\n\nAbout Qt")); connect(helpAboutQt, SIGNAL(triggered()), this, SLOT(slotAboutQt() ) ); @@ -1751,26 +2066,35 @@ void MainWindow::initMenuBar() { /** menuBar entry networkMenu */ networkMenu = menuBar()->addMenu(tr("&Network")); - networkMenu -> addAction(fileNew); - networkMenu -> addAction(fileOpen); + networkMenu -> addAction(networkNew); + networkMenu -> addAction(networkOpen); + networkMenu -> addSeparator(); + recentFilesSubMenu = new QMenu(tr("Recent files...")); + for (int i = 0; i < MaxRecentFiles; ++i) + recentFilesSubMenu->addAction(recentFileActs[i]); + + slotNetworkFileRecentUpdateActions(); + + networkMenu ->addMenu (recentFilesSubMenu ); + networkMenu -> addSeparator(); importSubMenu = new QMenu(tr("Import ...")); importSubMenu -> setIcon(QIcon(":/images/import.png")); - importSubMenu -> addAction(importPajek); - importSubMenu -> addAction(importSM); - importSubMenu -> addAction(importTwoModeSM); - importSubMenu -> addAction(importList); - importSubMenu -> addAction(importDL); - importSubMenu -> addAction(importDot); + importSubMenu -> addAction(networkImportPajek); + importSubMenu -> addAction(networkImportSM); + importSubMenu -> addAction(networkImportTwoModeSM); + importSubMenu -> addAction(networkImportList); + importSubMenu -> addAction(networkImportDL); + importSubMenu -> addAction(networkImportDot); networkMenu ->addMenu (importSubMenu); networkMenu -> addSeparator(); networkMenu -> addAction (openTextEditorAct); - networkMenu -> addAction (viewNetworkFileAct); + networkMenu -> addAction (networkViewFileAct); networkMenu -> addSeparator(); - networkMenu -> addAction (viewSociomatrixAct); + networkMenu -> addAction (networkViewSociomatrixAct); networkMenu -> addSeparator(); - networkMenu -> addAction (recreateDataSetAct); + networkMenu -> addAction (networkDataSetSelectAct); networkMenu -> addSeparator(); randomNetworkMenu = new QMenu(tr("Create Random Network...")); @@ -1788,27 +2112,27 @@ void MainWindow::initMenuBar() { networkMenu -> addAction(webCrawlerAct); networkMenu -> addSeparator(); - networkMenu -> addAction(fileSave); - networkMenu -> addAction(fileSaveAs); + networkMenu -> addAction(networkSave); + networkMenu -> addAction(networkSaveAs); networkMenu -> addSeparator(); exportSubMenu = networkMenu -> addMenu(tr("Export...")); - exportSubMenu -> addAction (exportBMP); - exportSubMenu -> addAction (exportPNG); - exportSubMenu -> addAction (exportPDF); + exportSubMenu -> addAction (networkExportBMP); + exportSubMenu -> addAction (networkExportPNG); + exportSubMenu -> addAction (networkExportPDF); exportSubMenu -> addSeparator(); - exportSubMenu -> addAction (exportSM); - exportSubMenu -> addAction (exportPajek); - // exportList->addTo(exportSubMenu); - // exportDL->addTo(exportSubMenu); - // exportGW->addTo(exportSubMenu); + exportSubMenu -> addAction (networkExportSM); + exportSubMenu -> addAction (networkExportPajek); + //exportSubMenu -> addAction (networkExportList); + //exportSubMenu -> addAction (networkExportDL); + //exportSubMenu -> addAction (networkExportGW); networkMenu -> addSeparator(); - networkMenu -> addAction(printNetwork); + networkMenu -> addAction(networkPrint); networkMenu -> addSeparator(); - networkMenu -> addAction(fileClose); - networkMenu -> addAction(fileQuit); + networkMenu -> addAction(networkClose); + networkMenu -> addAction(networkQuit); @@ -1816,36 +2140,69 @@ void MainWindow::initMenuBar() { /** menuBar entry editMenu */ editMenu = menuBar()->addMenu(tr("&Edit")); - editNodeMenu = new QMenu(tr("Node...")); + + editMenu -> addAction (editRelationPreviousAct); + editMenu -> addAction (editRelationNextAct); + editMenu -> addAction (editRelationAddAct); + + editMenu -> addSeparator(); + + editMenu -> addAction ( zoomInAct ); + editMenu -> addAction ( zoomOutAct ); + + editMenu -> addSeparator(); + + editMenu -> addAction ( editRotateLeftAct ); + editMenu -> addAction ( editRotateRightAct ); + + editMenu -> addSeparator(); + editMenu -> addAction (editResetSlidersAct ); + + editMenu -> addSeparator(); + editNodeMenu = new QMenu(tr("Nodes...")); editNodeMenu -> setIcon(QIcon(":/images/node.png")); editMenu -> addMenu ( editNodeMenu ); - editNodeMenu -> addAction (selectAllAct); - editNodeMenu -> addAction (selectNoneAct); + editNodeMenu -> addAction (editNodeSelectAllAct); + editNodeMenu -> addAction (editNodeSelectNoneAct); + + editNodeMenu -> addSeparator(); + + editNodeMenu -> addAction (editNodeFindAct); + editNodeMenu -> addAction (editNodeAddAct); + editNodeMenu -> addAction (editNodeRemoveAct); + + editNodeMenu -> addSeparator(); + + editNodeMenu -> addAction (editNodePropertiesAct); + editNodeMenu -> addSeparator(); - editNodeMenu -> addAction (findNodeAct); - editNodeMenu -> addAction (addNodeAct); - editNodeMenu -> addAction (removeNodeAct); + editNodeMenu -> addAction (editNodeColorAll); + editNodeMenu -> addAction (editNodeSizeAllAct); + editNodeMenu -> addAction (editNodeShapeAll); editNodeMenu -> addSeparator(); - editNodeMenu -> addAction (propertiesNodeAct); + editNodeMenu -> addAction (editNodeNumbersSizeAct); + editNodeMenu -> addAction (editNodeNumbersColorAct); editNodeMenu -> addSeparator(); - editNodeMenu -> addAction (changeAllNodesSizeAct); - editNodeMenu -> addAction (changeAllNodesShapeAct); - editNodeMenu -> addAction (changeNumbersSizeAct); - editNodeMenu -> addAction (changeLabelsSizeAct); + editNodeMenu -> addAction (editNodeLabelsSizeAct); + editNodeMenu -> addAction (editNodeLabelsColorAct); - editEdgeMenu = new QMenu(tr("Edge...")); + + editEdgeMenu = new QMenu(tr("Edges...")); editEdgeMenu -> setIcon(QIcon(":/images/line.png")); editMenu-> addMenu (editEdgeMenu); - editEdgeMenu -> addAction(addEdgeAct); - editEdgeMenu -> addAction(removeEdgeAct); - editEdgeMenu ->addSeparator(); - editEdgeMenu -> addAction(changeEdgeLabelAct); - editEdgeMenu -> addAction(changeEdgeColorAct); - editEdgeMenu -> addAction(changeEdgeWeightAct); - editEdgeMenu ->addSeparator(); - // transformNodes2EdgesAct -> addTo (editMenu); - editEdgeMenu -> addAction (symmetrizeAct); + editEdgeMenu -> addAction(editEdgeAddAct); + editEdgeMenu -> addAction(editEdgeRemoveAct); + editEdgeMenu -> addSeparator(); + editEdgeMenu -> addAction(editEdgeLabelAct); + editEdgeMenu -> addAction(editEdgeColorAct); + editEdgeMenu -> addAction(editEdgeWeightAct); + editEdgeMenu -> addSeparator(); + editEdgeMenu -> addAction (editEdgeColorAllAct); + editEdgeMenu -> addSeparator(); + editEdgeMenu -> addAction (editEdgeSymmetrizeAllAct); + editEdgeMenu -> addAction (editEdgeUndirectedAllAct); + // transformNodes2EdgesAct -> addTo (editMenu); editMenu ->addSeparator(); filterMenu = new QMenu ( tr("Filter...")); @@ -1857,76 +2214,11 @@ void MainWindow::initMenuBar() { filterMenu -> addAction(filterEdgesAct ); - editNodeMenu -> addSeparator(); - colorOptionsMenu=new QMenu(tr("Colors")); - colorOptionsMenu -> setIcon(QIcon(":/images/colorize.png")); - editMenu -> addMenu (colorOptionsMenu); - colorOptionsMenu -> addAction (changeBackColorAct); - colorOptionsMenu -> addAction (changeAllNodesColorAct); - colorOptionsMenu -> addAction (changeAllEdgesColorAct); - colorOptionsMenu -> addAction (changeAllNumbersColorAct); - colorOptionsMenu -> addAction (changeAllLabelsColorAct); - /** menuBar entry layoutMenu */ - layoutMenu = menuBar()->addMenu(tr("&Layout")); - // colorationMenu = new QPopupMenu(); - // layoutMenu -> insertItem (tr("Colorization"), colorationMenu); - // strongColorationAct -> addTo(colorationMenu); - // regularColorationAct-> addTo(colorationMenu); - // layoutMenu->insertSeparator(); - randomLayoutMenu = new QMenu(tr("Random...")); - layoutMenu -> addMenu (randomLayoutMenu ); - randomLayoutMenu -> addAction(randLayoutAct); - randomLayoutMenu -> addAction( randCircleLayoutAct ); - layoutMenu->addSeparator(); - circleLayoutMenu = new QMenu(tr("Circular by prominence index...")); - circleLayoutMenu -> setIcon(QIcon(":/images/circular.png")); - layoutMenu -> addMenu (circleLayoutMenu); - circleLayoutMenu -> addAction (layoutCircular_DC_Act); - circleLayoutMenu -> addAction (layoutCircular_CC_Act); - circleLayoutMenu -> addAction (layoutCircular_IRCC_Act); - circleLayoutMenu -> addAction (layoutCircular_BC_Act); - circleLayoutMenu -> addAction (layoutCircular_SC_Act); - circleLayoutMenu -> addAction (layoutCircular_EC_Act); - circleLayoutMenu -> addAction (layoutCircular_PC_Act); - circleLayoutMenu -> addAction (layoutCircular_IC_Act); - circleLayoutMenu -> addAction (layoutCircular_DP_Act); - circleLayoutMenu -> addAction (layoutCircular_PRP_Act); - circleLayoutMenu -> addAction (layoutCircular_PP_Act); - - levelLayoutMenu = new QMenu (tr("On levels by prominence index...")); - levelLayoutMenu -> setIcon(QIcon(":/images/net3.png")); - layoutMenu -> addMenu (levelLayoutMenu); - levelLayoutMenu -> addAction (layoutLevel_DC_Act); - levelLayoutMenu -> addAction (layoutLevel_CC_Act); - levelLayoutMenu -> addAction (layoutLevel_IRCC_Act); - levelLayoutMenu -> addAction (layoutLevel_BC_Act); - levelLayoutMenu -> addAction (layoutLevel_SC_Act); - levelLayoutMenu -> addAction (layoutLevel_EC_Act); - levelLayoutMenu -> addAction (layoutLevel_PC_Act); - levelLayoutMenu -> addAction (layoutLevel_IC_Act); - levelLayoutMenu -> addAction (layoutLevel_DP_Act); - levelLayoutMenu -> addAction (layoutLevel_PRP_Act); - levelLayoutMenu -> addAction (layoutLevel_PP_Act); - - layoutMenu->addSeparator(); - physicalLayoutMenu = new QMenu (tr("Force-Directed...")); - physicalLayoutMenu -> setIcon(QIcon(":/images/force.png")); - layoutMenu -> addMenu (physicalLayoutMenu); - physicalLayoutMenu -> addAction (springLayoutAct); - physicalLayoutMenu -> addAction (FRLayoutAct); - layoutMenu->addSeparator(); - layoutMenu->addAction(nodeSizesByOutDegreeAct); - layoutMenu->addAction(nodeSizesByInDegreeAct); - layoutMenu->addSeparator(); - layoutMenu -> addAction (clearGuidesAct); - - - - /** menuBar entry: statistics menu */ + /** menuBar entry: analyze menu */ statMenu = menuBar()->addMenu(tr("&Analyze")); statMenu -> addAction (symmetryAct); statMenu -> addAction (invertAdjMatrixAct); @@ -1974,37 +2266,101 @@ void MainWindow::initMenuBar() { centrlMenu -> addAction (cPageRankAct); centrlMenu -> addAction (cProximityPrestigeAct); + + /** menuBar entry layoutMenu */ + + layoutMenu = menuBar()->addMenu(tr("&Layout")); + // colorationMenu = new QPopupMenu(); + // layoutMenu -> insertItem (tr("Colorization"), colorationMenu); + // strongColorationAct -> addTo(colorationMenu); + // regularColorationAct-> addTo(colorationMenu); + // layoutMenu->insertSeparator(); + randomLayoutMenu = new QMenu(tr("Random...")); + layoutMenu -> addMenu (randomLayoutMenu ); + randomLayoutMenu -> addAction(randLayoutAct); + randomLayoutMenu -> addAction( randCircleLayoutAct ); + layoutMenu->addSeparator(); + + circleLayoutMenu = new QMenu(tr("Circular by prominence index...")); + circleLayoutMenu -> setIcon(QIcon(":/images/circular.png")); + layoutMenu -> addMenu (circleLayoutMenu); + circleLayoutMenu -> addAction (layoutCircular_DC_Act); + circleLayoutMenu -> addAction (layoutCircular_CC_Act); + circleLayoutMenu -> addAction (layoutCircular_IRCC_Act); + circleLayoutMenu -> addAction (layoutCircular_BC_Act); + circleLayoutMenu -> addAction (layoutCircular_SC_Act); + circleLayoutMenu -> addAction (layoutCircular_EC_Act); + circleLayoutMenu -> addAction (layoutCircular_PC_Act); + circleLayoutMenu -> addAction (layoutCircular_IC_Act); + circleLayoutMenu -> addAction (layoutCircular_DP_Act); + circleLayoutMenu -> addAction (layoutCircular_PRP_Act); + circleLayoutMenu -> addAction (layoutCircular_PP_Act); + + levelLayoutMenu = new QMenu (tr("On levels by prominence index...")); + levelLayoutMenu -> setIcon(QIcon(":/images/net3.png")); + layoutMenu -> addMenu (levelLayoutMenu); + levelLayoutMenu -> addAction (layoutLevel_DC_Act); + levelLayoutMenu -> addAction (layoutLevel_CC_Act); + levelLayoutMenu -> addAction (layoutLevel_IRCC_Act); + levelLayoutMenu -> addAction (layoutLevel_BC_Act); + levelLayoutMenu -> addAction (layoutLevel_SC_Act); + levelLayoutMenu -> addAction (layoutLevel_EC_Act); + levelLayoutMenu -> addAction (layoutLevel_PC_Act); + levelLayoutMenu -> addAction (layoutLevel_IC_Act); + levelLayoutMenu -> addAction (layoutLevel_DP_Act); + levelLayoutMenu -> addAction (layoutLevel_PRP_Act); + levelLayoutMenu -> addAction (layoutLevel_PP_Act); + + layoutMenu->addSeparator(); + physicalLayoutMenu = new QMenu (tr("Force-Directed...")); + physicalLayoutMenu -> setIcon(QIcon(":/images/force.png")); + layoutMenu -> addMenu (physicalLayoutMenu); + physicalLayoutMenu -> addAction (springLayoutAct); + physicalLayoutMenu -> addAction (FRLayoutAct); + layoutMenu->addSeparator(); + layoutMenu->addAction(nodeSizesByOutDegreeAct); + layoutMenu->addAction(nodeSizesByInDegreeAct); + layoutMenu->addSeparator(); + layoutMenu -> addAction (layoutGuidesAct); + + + /** menuBar entry optionsMenu */ optionsMenu = menuBar()->addMenu(tr("&Options")); nodeOptionsMenu=new QMenu(tr("Nodes...")); nodeOptionsMenu -> setIcon(QIcon(":/images/nodes.png")); optionsMenu -> addMenu (nodeOptionsMenu); - nodeOptionsMenu -> addAction (displayNodeNumbersAct); - nodeOptionsMenu -> addAction (displayNodeLabelsAct); - nodeOptionsMenu -> addAction (displayNumbersInsideNodesAct); + nodeOptionsMenu -> addAction (optionsNodeNumbersVisibilityAct); + nodeOptionsMenu -> addAction (optionsNodeLabelsVisibilityAct); + nodeOptionsMenu -> addAction (optionsNodeNumbersInsideAct); edgeOptionsMenu=new QMenu(tr("Edges...")); edgeOptionsMenu -> setIcon(QIcon(":/images/line.png")); optionsMenu -> addMenu (edgeOptionsMenu); - edgeOptionsMenu -> addAction (displayEdgesAct); - edgeOptionsMenu -> addAction (displayEdgesWeightNumbersAct); + edgeOptionsMenu -> addAction (optionsEdgesVisibilityAct); + edgeOptionsMenu -> addSeparator(); + edgeOptionsMenu -> addAction (optionsEdgeWeightNumbersAct); edgeOptionsMenu -> addAction (considerEdgeWeightsAct); - edgeOptionsMenu -> addAction (displayEdgesArrowsAct ); + edgeOptionsMenu -> addAction (optionsEdgeThicknessPerWeightAct); + edgeOptionsMenu -> addSeparator(); + edgeOptionsMenu -> addAction (optionsEdgeLabelsAct); + edgeOptionsMenu -> addSeparator(); + edgeOptionsMenu -> addAction (optionsEdgeArrowsAct ); edgeOptionsMenu -> addSeparator(); - edgeOptionsMenu -> addAction (drawEdgesWeightsAct); edgeOptionsMenu -> addAction (drawEdgesBezier); viewOptionsMenu = new QMenu (tr("&View...")); viewOptionsMenu -> setIcon(QIcon(":/images/view.png")); optionsMenu -> addMenu (viewOptionsMenu); - viewOptionsMenu-> addAction (backgroundImageAct); - viewOptionsMenu-> addAction (antialiasingAct); - viewOptionsMenu-> addAction (printDebugAct); - viewOptionsMenu-> addAction (showProgressBarAct); - viewOptionsMenu-> addAction (viewToolBar); - viewOptionsMenu-> addAction (viewStatusBar); + viewOptionsMenu -> addAction (changeBackColorAct); + viewOptionsMenu -> addAction (backgroundImageAct); + + + optionsMenu -> addSeparator(); + optionsMenu -> addAction (openSettingsAct); + /** menuBar entry helpMenu */ @@ -2012,6 +2368,8 @@ void MainWindow::initMenuBar() { helpMenu -> addAction (helpApp); helpMenu -> addAction (tipsApp); helpMenu -> addSeparator(); + helpMenu -> addAction (helpCheckUpdatesApp); + helpMenu -> addSeparator(); helpMenu-> addAction (helpAboutApp); helpMenu-> addAction (helpAboutQt); @@ -2026,53 +2384,40 @@ void MainWindow::initMenuBar() { void MainWindow::initToolBar(){ toolBar = addToolBar("operations"); - toolBar -> addAction (fileNew); - toolBar -> addAction (fileOpen); - toolBar -> addAction (fileSave); - toolBar -> addAction (printNetwork); - toolBar -> addSeparator(); - - toolBar -> addAction(zoomInAct); - - //Create zooming widget - zoomCombo = new QComboBox; - QStringList scales; - scales << tr("25%") << tr("50%") << tr("75%") << tr("100%") << tr("125%") << tr("150%")<addItems(scales); - zoomCombo->setCurrentIndex(3); - - toolBar -> addWidget(zoomCombo); - toolBar -> addAction(zoomOutAct); - + toolBar -> addAction (networkNew); + toolBar -> addAction (networkOpen); + toolBar -> addAction (networkSave); + toolBar -> addAction (networkPrint); toolBar -> addSeparator(); QLabel *labelRotateSpinBox= new QLabel; labelRotateSpinBox ->setText(tr("Rotation:")); - rotateSpinBox = new QSpinBox; - rotateSpinBox ->setRange(-360, 360); - rotateSpinBox->setSingleStep(1); - rotateSpinBox->setValue(0); - - toolBar -> addWidget(labelRotateSpinBox); - toolBar -> addWidget(rotateSpinBox); - toolBar -> addSeparator(); //Create relation select widget QLabel *labelRelationSelect= new QLabel; labelRelationSelect ->setText(tr("Relation:")); toolBar -> addWidget (labelRelationSelect); - toolBar -> addAction (prevRelationAct); - changeRelationCombo = new QComboBox; - changeRelationCombo->setCurrentIndex(0); - toolBar -> addWidget(changeRelationCombo); - toolBar -> addAction (nextRelationAct); - toolBar -> addAction (addRelationAct); + toolBar -> addAction (editRelationPreviousAct); + editRelationChangeCombo = new QComboBox; + editRelationChangeCombo->setMinimumWidth(180); + editRelationChangeCombo->setCurrentIndex(0); + editRelationChangeCombo->setToolTip( + tr("Displays current relation - Click to change graph relation")); + editRelationChangeCombo->setStatusTip( + tr("Displays current relation - Click to change graph relation")); + editRelationChangeCombo->setWhatsThis( + tr("Previous Relation\n\n" + "Displays current relation - Click to change graph relation (if any)")); + + toolBar -> addWidget(editRelationChangeCombo); + toolBar -> addAction (editRelationNextAct); + toolBar -> addAction (editRelationAddAct); toolBar -> addSeparator(); toolBar -> addAction ( QWhatsThis::createAction (this)); - + toolBar -> setIconSize(QSize(16,16)); } @@ -2081,20 +2426,30 @@ void MainWindow::initToolBar(){ -//Creates a dock widget for instant menu access + +/** + * @brief MainWindow::initToolBox + * Creates a dock widget for instant menu access + */ void MainWindow::initToolBox(){ - toolBox = new QTabWidget; - //toolBox->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Ignored)); /* * create widgets for the Controls Tab */ // create 4 buttons for the Edit groupbox - addNodeBt= new QPushButton(QIcon(":/images/add.png"),tr("&Add Node")); - addNodeBt->setFocusPolicy(Qt::NoFocus); - addNodeBt->setToolTip( - tr("Add a new node to the network (Ctrl+X, Ctrl+A). \n\n " + editNodeAddBt= new QPushButton(QIcon(":/images/add.png"),tr("&Add Node")); + editNodeAddBt->setFocusPolicy(Qt::NoFocus); + editNodeAddBt->setMinimumWidth(100); + editNodeAddBt->setStatusTip( tr("Add a new node to the network.") ) ; + editNodeAddBt->setToolTip( + tr("Add a new node to the network (Ctrl+.). \n\n " + "You can also create a new node \n" + "in a specific position by double-clicking \n") + ); + editNodeAddBt->setWhatsThis( + tr("Add new node\n\n" + "Adds a new node to the network (Ctrl+.). \n\n " "Alternately, you can create a new node \n" "in a specific position by double-clicking \n" "on that spot of the canvas.") @@ -2102,89 +2457,160 @@ void MainWindow::initToolBox(){ removeNodeBt= new QPushButton(QIcon(":/images/remove.png"),tr("&Remove Node")); removeNodeBt->setFocusPolicy(Qt::NoFocus); + removeNodeBt->setMinimumWidth(100); + removeNodeBt->setStatusTip( tr("Remove a node from the network. ") ); removeNodeBt->setToolTip( - tr("Remove a node from the network. \n\n " + tr("Remove a node from the network (Ctrl+Alt+.). ") + ); + + removeNodeBt->setWhatsThis( + tr("Remove node\n\n" + "Removes a node from the network (Ctrl+Alt+.). \n\n " "Alternately, you can remove a node \n" "by right-clicking on it.") ); - addEdgeBt= new QPushButton(QIcon(":/images/connect.png"),tr("Add &Edge")); - addEdgeBt->setFocusPolicy(Qt::NoFocus); - addEdgeBt->setToolTip( - tr("Add a new Edge from a node to another (Ctrl+E,Ctrl+A).\n\n " - "Alternately, you can create a new edge between two \n" - "nodes by middle-clicking on them consecutively.") + editEdgeAddBt= new QPushButton(QIcon(":/images/connect.png"),tr("Add &Edge")); + editEdgeAddBt->setFocusPolicy(Qt::NoFocus); + editEdgeAddBt->setMinimumWidth(100); + editEdgeAddBt->setStatusTip( + tr("Add a new Edge from a node to another. ") + ); + editEdgeAddBt->setToolTip( + tr("Add a new Edge from a node to another (Ctrl+/).\n\n " + "You can also create an edge between two nodes\n" + "by double-clicking or middle-clicking on them consecutively.") + ); + editEdgeAddBt->setWhatsThis( + tr("Add edge\n\n" + "Adds a new Edge from a node to another (Ctrl+/).\n\n " + "Alternately, you can create a new edge between two nodes\n" + "by double-clicking or middle-clicking on them consecutively.") ); - removeEdgeBt= new QPushButton(QIcon(":/images/disconnect.png"),tr("Remove Edge")); - removeEdgeBt->setFocusPolicy(Qt::NoFocus); - removeEdgeBt->setToolTip( - tr("Remove an Edge from the network \n\n " + editEdgeRemoveBt= new QPushButton(QIcon(":/images/disconnect.png"),tr("Remove Edge")); + editEdgeRemoveBt->setFocusPolicy(Qt::NoFocus); + editEdgeRemoveBt->setMinimumWidth(100); + editEdgeRemoveBt->setStatusTip( tr("Remove an Edge from the network ") ); + editEdgeRemoveBt->setToolTip( + tr("Remove an Edge from the network (Ctrl+Alt+/)" + ) + ); + editEdgeRemoveBt->setWhatsThis( + tr("Remove edge\n\n" + "Removes an Edge from the network (Ctrl+Alt+/)." "Alternately, you can remove an Edge \n" "by right-clicking on it." ) ); + //create a grid layout for these buttons QGridLayout *buttonsGrid = new QGridLayout; - buttonsGrid -> addWidget(addNodeBt, 0,0); + buttonsGrid -> addWidget(editNodeAddBt, 0,0); buttonsGrid -> addWidget(removeNodeBt, 0,1); - buttonsGrid -> addWidget(addEdgeBt,1,0); - buttonsGrid -> addWidget(removeEdgeBt,1,1); - buttonsGrid->setSpacing(10); - buttonsGrid->setMargin(0); + buttonsGrid -> addWidget(editEdgeAddBt,1,0); + buttonsGrid -> addWidget(editEdgeRemoveBt,1,1); + buttonsGrid -> setSpacing(5); + buttonsGrid -> setContentsMargins(5, 5, 5, 5); - //create a groupbox "Edit" - Inside, display the vertical layout of widgets + //create a groupbox "Edit" - Inside, display the grid layout of widgets QGroupBox *editGroupBox= new QGroupBox(tr("Edit")); editGroupBox->setLayout(buttonsGrid); - editGroupBox->setMaximumSize(300,100); + editGroupBox->setMaximumWidth(280); + editGroupBox->setMinimumHeight(100); + //create widgets for the "Analysis" box QLabel *toolBoxAnalysisGeodesicsSelectLabel = new QLabel; toolBoxAnalysisGeodesicsSelectLabel->setText(tr("Distances:")); + toolBoxAnalysisGeodesicsSelectLabel->setMinimumWidth(115); toolBoxAnalysisGeodesicsSelect = new QComboBox; + toolBoxAnalysisGeodesicsSelect -> setStatusTip( + tr("Basic graph-theoretic metrics i.e. diameter.")); + toolBoxAnalysisGeodesicsSelect -> setToolTip( + tr("Compute basic graph-theoretic features of the network, " + "i.e. diameter.")); + toolBoxAnalysisGeodesicsSelect -> setWhatsThis( + tr("Analyze Distances\n\n" + "Compute basic graph-theoretic features of the network " + "i.e. diameter, eccentricity, distances etc.")); QStringList geodesicsCommandsList; geodesicsCommandsList << "None selected" << "Distance" << "Average Distance" << "Distances Matrix" << "Geodesics Matrix" << "Eccentricity" << "Diameter"; toolBoxAnalysisGeodesicsSelect->addItems(geodesicsCommandsList); -// toolBoxAnalysisGeodesicsSelect->setMaximumHeight(20); + toolBoxAnalysisGeodesicsSelect->setMinimumWidth(115); + QLabel *toolBoxAnalysisConnectivitySelectLabel = new QLabel; toolBoxAnalysisConnectivitySelectLabel->setText(tr("Connectivity:")); + toolBoxAnalysisConnectivitySelectLabel->setMinimumWidth(115); toolBoxAnalysisConnectivitySelect = new QComboBox; + toolBoxAnalysisConnectivitySelect->setStatusTip( + tr("'Connectivity' metrics i.e. connectedness, walks, etc.")); + toolBoxAnalysisConnectivitySelect->setToolTip( + tr("Compute 'connectivity' metrics such as network connectedness, " + "walks, reachability etc.")); + toolBoxAnalysisConnectivitySelect->setWhatsThis( + tr("Analyze Connectivity\\n\n" + "Compute 'connectivity' metrics such as network connectedness, " + "walks, reachability etc.")); QStringList connectivityCommands; connectivityCommands << "None selected" << "Connectedness" << "Walks of given length" << "Total Walks" << "Reachability Matrix"; toolBoxAnalysisConnectivitySelect->addItems(connectivityCommands); -// toolBoxAnalysisConnectivitySelect->setMaximumHeight(20); + toolBoxAnalysisConnectivitySelect->setMinimumWidth(115); + QLabel *toolBoxAnalysisClusterabilitySelectLabel = new QLabel; toolBoxAnalysisClusterabilitySelectLabel->setText(tr("Clusterability:")); + toolBoxAnalysisClusterabilitySelectLabel->setMinimumWidth(115); toolBoxAnalysisClusterabilitySelect = new QComboBox; + toolBoxAnalysisClusterabilitySelect->setStatusTip( + tr("'Clusterability' metrics, i.e. cliques")); + toolBoxAnalysisClusterabilitySelect->setToolTip( + tr("Compute 'clusterability' metrics, such as cliques")); + toolBoxAnalysisClusterabilitySelect->setWhatsThis( + tr("Analyze Clusterability\n\n" + "Compute 'clusterability' metrics, such as cliques")); QStringList clusterabilityCommands; clusterabilityCommands << "None selected" << "Cliques" << "Clustering Coefficient" << "Triad Census"; toolBoxAnalysisClusterabilitySelect->addItems(clusterabilityCommands); + toolBoxAnalysisClusterabilitySelect->setMinimumWidth(115); QLabel *toolBoxAnalysisProminenceSelectLabel = new QLabel; toolBoxAnalysisProminenceSelectLabel->setText(tr("Prominence:")); + toolBoxAnalysisProminenceSelectLabel->setMinimumWidth(115); toolBoxAnalysisProminenceSelect = new QComboBox; + toolBoxAnalysisProminenceSelect -> setStatusTip( + tr("Metrics of how 'prominent' or important each node is.") + ); toolBoxAnalysisProminenceSelect -> setToolTip( - tr("Various metrics to calculate how 'prominent' or important each actor (node) is inside the network.\n\n") + tr("Compute metrics to see how 'prominent' or " + "important each actor (node) is inside the network.") + ); + toolBoxAnalysisProminenceSelect -> setWhatsThis( + tr("Analyze Prominence\n\n" + "Computes various metrics to see how 'prominent' or " + "important each actor (node) is inside the network.") ); toolBoxAnalysisProminenceSelect -> setWhatsThis( - tr("Various metrics to calculate how 'prominent' or important each actor (node) is inside the network.\n\n") + - tr("Centrality metrics quantify how central is each node by examining its ties and its geodesic distances (shortest path lengths) to other nodes. ")+ - tr("Most Centrality indices were designed for undirected graphs.\n\n")+ - tr("Prestige indices focus on \"choices received\" to a node. \n")+ - tr("These indices measure the nominations or ties to each node from all others (or inLinks). ") + - tr("Prestige indices are suitable (and can be calculated only) on directed graphs.") + tr("Analyze Prominence\n\n" + "Computes various metrics to see how 'prominent' or " + "important each actor (node) is inside the network.\n\n" + "Centrality metrics quantify how central is each node by examining " + "its ties and its geodesic distances (shortest path lengths) to other nodes. " + "Most Centrality indices were designed for undirected graphs.\n\n" + "Prestige indices focus on \"choices received\" to a node. \n" + "These indices measure the nominations or ties to each node from all others (or inLinks). " + "Prestige indices are suitable (and can be calculated only) on directed graphs.") ); QStringList prominenceCommands; prominenceCommands << "None selected" @@ -2193,10 +2619,10 @@ void MainWindow::initToolBox(){ << "Betweenness Centrality" << "Stress Centrality" << "Eccentricity Centrality" << "Power Centrality" << "Information Centrality" - << "Degree Prestige (inDegree)" << "PageRank Prestige" + << "Degree Prestige (in-Degree)" << "PageRank Prestige" << "Proximity Prestige"; toolBoxAnalysisProminenceSelect->addItems(prominenceCommands); -// toolBoxAnalysisProminenceSelect->setMaximumHeight(20); + toolBoxAnalysisProminenceSelect->setMinimumWidth(115); //create layout for analysis options QGridLayout *analysisGrid = new QGridLayout(); @@ -2208,38 +2634,60 @@ void MainWindow::initToolBox(){ analysisGrid -> addWidget(toolBoxAnalysisClusterabilitySelect, 3,1); analysisGrid -> addWidget(toolBoxAnalysisProminenceSelectLabel, 4,0); analysisGrid -> addWidget(toolBoxAnalysisProminenceSelect, 4,1); - //layoutByIndexGrid -> setRowStretch(0,1); //fix stretch + analysisGrid -> setSpacing(5); + analysisGrid -> setContentsMargins(15, 5, 15, 5); + //create a box and set the above layout inside QGroupBox *analysisBox= new QGroupBox(tr("Analyze")); - analysisBox->setMaximumWidth(300); + analysisBox->setMinimumHeight(170); + analysisBox->setMaximumWidth(280); analysisBox->setLayout (analysisGrid ); //create widgets for the "Visualization By Index" box QLabel *toolBoxLayoutByIndexSelectLabel = new QLabel; toolBoxLayoutByIndexSelectLabel->setText(tr("Index:")); + toolBoxLayoutByIndexSelectLabel->setMinimumWidth(110); toolBoxLayoutByIndexSelect = new QComboBox; + toolBoxLayoutByIndexSelect->setStatusTip(tr("Select a prominence-based layout model")); + toolBoxLayoutByIndexSelect->setToolTip(tr("Apply a prominence-based layout model")); + toolBoxLayoutByIndexSelect->setWhatsThis( + tr("Visualize by prominence index\n\n" + "Apply a prominence-based layout model to the network. \n" + "For instance, you can apply a degree centrality layout. " + "For each prominence index, you can select a circular or level layout type.")); QStringList indicesList; - indicesList << "None/Original"<< "Random" + indicesList << "None"<< "Random" << "Degree Centrality" << "Closeness Centrality" << "Influence Range Closeness Centrality" << "Betweenness Centrality" << "Stress Centrality" << "Eccentricity Centrality" << "Power Centrality" << "Information Centrality" - << "Degree Prestige (inDegree)" << "PageRank Prestige" + << "Degree Prestige (in-Degree)" << "PageRank Prestige" << "Proximity Prestige"; toolBoxLayoutByIndexSelect->addItems(indicesList); toolBoxLayoutByIndexSelect->setMinimumHeight(20); + toolBoxLayoutByIndexSelect->setMinimumWidth(120); QLabel *toolBoxLayoutByIndexTypeLabel = new QLabel; toolBoxLayoutByIndexTypeLabel->setText(tr("Layout Type:")); + toolBoxLayoutByIndexTypeLabel->setMinimumWidth(10); toolBoxLayoutByIndexTypeSelect = new QComboBox; + toolBoxLayoutByIndexTypeSelect->setStatusTip( + tr("Select layout type for the selected model")); + toolBoxLayoutByIndexTypeSelect->setToolTip( + tr("Select circular or level layout type (you must select an index above)")); + toolBoxLayoutByIndexTypeSelect->setWhatsThis( + tr("Layout Type\n\n" + "Select a layout type (circular or level) for the selected prominence-based model " + "you want to apply to the network.")); QStringList layoutTypes; layoutTypes << "Circular" << "On Levels" << "Nodal size"; toolBoxLayoutByIndexTypeSelect->addItems(layoutTypes); toolBoxLayoutByIndexTypeSelect->setMinimumHeight(20); + toolBoxLayoutByIndexTypeSelect->setMinimumWidth(120); toolBoxLayoutByIndexButton = new QPushButton(tr("Apply")); toolBoxLayoutByIndexButton->setFocusPolicy(Qt::NoFocus); @@ -2254,192 +2702,314 @@ void MainWindow::initToolBox(){ layoutByIndexGrid -> addWidget(toolBoxLayoutByIndexTypeLabel, 1,0); layoutByIndexGrid -> addWidget(toolBoxLayoutByIndexTypeSelect, 1,1); layoutByIndexGrid -> addWidget(toolBoxLayoutByIndexButton, 2,1); - //layoutByIndexGrid -> setRowStretch(0,1); //fix stretch + layoutByIndexGrid -> setSpacing(5); + layoutByIndexGrid -> setContentsMargins(5, 5, 5, 5); //create a box and set the above layout inside QGroupBox *layoutByIndexBox= new QGroupBox(tr("By Prominence Index")); - layoutByIndexBox->setMaximumWidth(300); + layoutByIndexBox->setMinimumHeight(120); layoutByIndexBox->setLayout (layoutByIndexGrid ); - // create widgets for the "Force-Directed Models" groupBox - layoutEadesBx = new QCheckBox(tr("Spring Embedder (Eades)") ); - layoutEadesBx->setEnabled(true); - layoutEadesBx->setChecked(false); - layoutEadesBx - ->setToolTip( - tr("Embeds a spring-gravitational model on the network, where \n" - "each node is regarded as physical object (ring) repeling all \n" - "other nodes, while springs between connected nodes attract them. \n" - "This is a very SLOW process on networks with N > 100!")); - - layoutFruchtermanBx = new QCheckBox(tr("Fruchterman-Reingold") ); - layoutFruchtermanBx->setEnabled(true); - layoutFruchtermanBx->setChecked(false); - layoutFruchtermanBx - ->setToolTip( - tr("In Fruchterman-Reingold model, the vertices behave as atomic \n" - "particles or celestial bodies, exerting attractive and repulsive \n" - "forces to each other. Again, only vertices that are neighbours \n" - "attract each other but, unlike Eades Spring Embedder, all vertices \n" - "repel each other. ")); + // create widgets for the "Force-Directed Models" Box + QLabel *toolBoxLayoutForceDirectedSelectLabel = new QLabel; + toolBoxLayoutForceDirectedSelectLabel->setText(tr("Model:")); + toolBoxLayoutForceDirectedSelectLabel->setMinimumWidth(110); + toolBoxLayoutForceDirectedSelect = new QComboBox; + QStringList modelsList; + modelsList << tr("None") + << tr("Spring Embedder (Eades)") + << tr("Fruchterman-Reingold") + << tr("Kamada-Kawai") ; + + toolBoxLayoutForceDirectedSelect->addItems(modelsList); + toolBoxLayoutForceDirectedSelect->setMinimumHeight(20); + toolBoxLayoutForceDirectedSelect->setMinimumWidth(120); + toolBoxLayoutForceDirectedSelect->setStatusTip ( + tr("Select a Force-Directed layout model. ")); + toolBoxLayoutForceDirectedSelect->setToolTip ( + tr("Select a Force-Directed layout model to embed to the network\n\n" + "Available models: \n" + "Eades:\n" + "A spring-gravitational model, where each node is \n" + "regarded as physical object (ring) repeling all other \n" + "nodes, while springs between connected nodes attract them. \n\n" + + "Fruchterman-Reingold: Vertices that are neighbours " + "attract each other but, unlike Eades Spring " + "Embedder, all vertices repel each other.\n\n" + "Kamada-Kawai\n" + "Every two vertices are connected by a 'spring' of a \n" + "desirable length, which corresponds to their graph theoretic \n" + "distance. In this way, the optimal layout of the graph \n" + "is the state with the minimum imbalance. The degree of \n" + "imbalance is formulated as the total spring energy: \n" + "the square summation of the differences between desirable \n" + "distances and real ones for all pairs of vertices" + ) + ); + toolBoxLayoutForceDirectedSelect->setWhatsThis( + tr("Visualize by a Force-Directed layout model.\n\n" + "Available models: \n\n " + "Eades model\n " + "A spring-gravitational model, where each node is \n" + "regarded as physical object (ring) repeling all other \n" + "nodes, while springs between connected nodes attract them. \n\n" + + "Fruchterman-Reingold\n" + "In this model, the vertices behave as atomic particles \n" + "or celestial bodies, exerting attractive and repulsive \n" + "forces to each other. Again, only vertices that are \n" + "neighbours attract each other but, unlike Eades Spring \n" + "Embedder, all vertices repel each other.\n\n" + "Kamada-Kawai\n" + "In this model, the graph is considered to be a dynamic system \n" + "where every two vertices are connected by a 'spring' of a \n" + "desirable length, which corresponds to their graph theoretic \n" + "distance. In this way, the optimal layout of the graph \n" + "is the state with the minimum imbalance. The degree of \n" + "imbalance is formulated as the total spring energy: \n" + "the square summation of the differences between desirable \n" + "distances and real ones for all pairs of vertices" + ) + ); - layoutKamandaBx= new QCheckBox(tr("Kamanda-Kawai") ); - layoutKamandaBx->setEnabled(false); - layoutKamandaBx->setToolTip(tr("!")); + toolBoxLayoutForceDirectedButton = new QPushButton(tr("Apply")); + toolBoxLayoutForceDirectedButton->setFocusPolicy(Qt::NoFocus); + toolBoxLayoutForceDirectedButton->setMinimumHeight(20); + toolBoxLayoutForceDirectedButton->setMaximumWidth(60); //create layout for dynamic visualisation QGridLayout *layoutForceDirectedGrid = new QGridLayout(); - layoutForceDirectedGrid -> addWidget(layoutEadesBx, 0,0); - layoutForceDirectedGrid -> addWidget(layoutFruchtermanBx, 1,0); - layoutForceDirectedGrid -> addWidget(layoutKamandaBx, 2,0); - layoutForceDirectedGrid->setSpacing(10); - layoutForceDirectedGrid->setMargin(0); + layoutForceDirectedGrid -> addWidget(toolBoxLayoutForceDirectedSelectLabel, 0,0); + layoutForceDirectedGrid -> addWidget(toolBoxLayoutForceDirectedSelect, 0,1); + layoutForceDirectedGrid -> addWidget(toolBoxLayoutForceDirectedButton, 1,1); + layoutForceDirectedGrid -> setSpacing(5); + layoutForceDirectedGrid -> setContentsMargins(5,5, 5, 5); //create a box for dynamic layout options QGroupBox *layoutDynamicBox= new QGroupBox(tr("By Force-Directed Model")); - layoutDynamicBox->setMaximumWidth(300); + layoutDynamicBox->setMinimumHeight(90); layoutDynamicBox->setLayout (layoutForceDirectedGrid ); //create widgets for additional visualization options box - nodeSizesByOutDegreeBx = new QCheckBox( + toolBoxNodeSizesByOutDegreeBx = new QCheckBox( tr("Node sizes by OutDegree") ); - nodeSizesByOutDegreeBx ->setEnabled(true); - nodeSizesByOutDegreeBx + toolBoxNodeSizesByOutDegreeBx ->setEnabled(true); + toolBoxNodeSizesByOutDegreeBx + ->setStatusTip( + tr("Enable to have all nodes resized so that their " + "size reflect their out-degree.")); + + toolBoxNodeSizesByOutDegreeBx ->setToolTip( - tr("If you enable this, all nodes will be resized so that their " - "size reflect their out-degree. \n" - "Nodes with more directed edges starting from them will be bigger...")); + tr("If you enable this, all nodes will be resized " + "so that their size reflect their out-degree. \n" + "Nodes with more outbound directed edges will be bigger...")); - nodeSizesByInDegreeBx = new QCheckBox( + toolBoxNodeSizesByInDegreeBx = new QCheckBox( tr("Node sizes by InDegree") ); - nodeSizesByInDegreeBx ->setEnabled(true); - nodeSizesByInDegreeBx + toolBoxNodeSizesByInDegreeBx ->setEnabled(true); + toolBoxNodeSizesByInDegreeBx + ->setStatusTip( + tr("Enable to have all nodes resized so that their " + "size reflect their in-degree." ) ); + toolBoxNodeSizesByInDegreeBx ->setToolTip( - tr("If you enable this, all nodes will be resized so that their " - "size reflect their in-degree. \n" - "Nodes with more directed edges ending at them will be bigger...")); + tr("If you enable this, all nodes will be resized " + "so that their size reflect their in-degree. \n" + "Nodes with more inbound directed edges them will be bigger...")); - layoutGuidesBx = new QCheckBox( + toolBoxLayoutGuidesBx = new QCheckBox( tr("Layout guidelines") ); - layoutGuidesBx ->setEnabled(true); - layoutGuidesBx ->setChecked(true); - layoutGuidesBx->setToolTip( - tr("Disable to not display layout guidelines")); + toolBoxLayoutGuidesBx->setToolTip( + tr("Toggle layout guidelines on or off.")); + + toolBoxLayoutGuidesBx ->setStatusTip(tr("Toggle layout guidelines on or off.")); + toolBoxLayoutGuidesBx->setWhatsThis(tr("Layout Guidelines\n\n" + "Layout Guidelines are circular or horizontal lines \n" + "usually created when embedding prominence-based \n" + "visualization models on the network.\n" + "Disable this checkbox to hide guidelines")); + toolBoxLayoutGuidesBx ->setEnabled(true); + toolBoxLayoutGuidesBx ->setChecked(true); + + + QGridLayout *layoutOptionsGrid = new QGridLayout(); - layoutOptionsGrid -> addWidget(nodeSizesByOutDegreeBx, 0,0); - layoutOptionsGrid -> addWidget(nodeSizesByInDegreeBx, 1,0); - layoutOptionsGrid -> addWidget(layoutGuidesBx, 2,0); - layoutOptionsGrid->setSpacing(10); - layoutOptionsGrid->setMargin(0); + layoutOptionsGrid -> addWidget(toolBoxNodeSizesByOutDegreeBx, 0,0); + layoutOptionsGrid -> addWidget(toolBoxNodeSizesByInDegreeBx, 1,0); + layoutOptionsGrid -> addWidget(toolBoxLayoutGuidesBx, 2,0); + layoutOptionsGrid->setSpacing(5); + layoutOptionsGrid->setContentsMargins(5, 5, 5, 5); - //Box for additional layout options - QGroupBox *layoutOptionsBox= new QGroupBox(tr("Options")); - layoutOptionsBox->setMaximumWidth(300); - layoutOptionsBox->setLayout (layoutOptionsGrid ); + //Box for additional visualization options + QGroupBox *visualizeOptionsBox= new QGroupBox(tr("Options")); + visualizeOptionsBox->setMinimumHeight(110); + visualizeOptionsBox->setMaximumWidth(280); + visualizeOptionsBox->setLayout (layoutOptionsGrid ); //Parent box with vertical layout for all layout/visualization boxes QVBoxLayout *visualizationBoxLayout = new QVBoxLayout; visualizationBoxLayout -> addWidget(layoutByIndexBox); visualizationBoxLayout -> addWidget(layoutDynamicBox); - visualizationBoxLayout -> addWidget(layoutOptionsBox); + visualizationBoxLayout -> addWidget(visualizeOptionsBox); + QGroupBox *visualizationBox= new QGroupBox(tr("Visualize")); - visualizationBox->setMaximumWidth(300); + visualizationBox->setMaximumWidth(280); visualizationBox->setLayout (visualizationBoxLayout ); //Parent box with vertical layout for all boxes of Controls - QVBoxLayout *controlTabVerticalLayout = new QVBoxLayout; - controlTabVerticalLayout -> addWidget(editGroupBox); - controlTabVerticalLayout -> addWidget(analysisBox); - controlTabVerticalLayout -> addWidget(visualizationBox); - controlTabVerticalLayout->setSpacing(0); - controlTabVerticalLayout->setMargin(0); - - QGroupBox *controlGroupBox = new QGroupBox; - controlGroupBox->setLayout(controlTabVerticalLayout); - controlGroupBox->setMaximumWidth(300); - controlGroupBox->setContentsMargins(0,0,0,0); - toolBox->addTab(controlGroupBox, tr("Controls")); - - - connect(layoutEadesBx, SIGNAL(clicked(bool)), - this, SLOT(slotLayoutSpringEmbedder(bool))); - connect(layoutFruchtermanBx, SIGNAL(stateChanged(int)), - this, SLOT(layoutFruchterman(int))); - - connect(nodeSizesByOutDegreeBx , SIGNAL(clicked(bool)), - this, SLOT(slotLayoutNodeSizesByOutDegree(bool))); - connect(nodeSizesByInDegreeBx , SIGNAL(clicked(bool)), - this, SLOT(slotLayoutNodeSizesByInDegree(bool))); + QGridLayout *editGrid = new QGridLayout; + editGrid -> addWidget(editGroupBox, 0,0); + editGrid -> addWidget(analysisBox, 1, 0); + editGrid -> addWidget(visualizationBox, 2, 0); + editGrid -> setRowStretch(3,1); //fix stretch + //create a box with title + leftPanel = new QGroupBox(tr("Control Panel")); + leftPanel -> setLayout (editGrid); //create widgets for Properties/Statistics group/tab QLabel *labelNodesLCD = new QLabel; labelNodesLCD->setText(tr("Total Nodes")); - QLabel *labelEdgesLCD = new QLabel; - labelEdgesLCD->setText(tr("Total Edges (Arcs)")); + labelNodesLCD->setToolTip(tr("The total number of nodes (vertices) in the network.")); + labelEdgesLCD = new QLabel; + labelEdgesLCD->setText(tr("Total Arcs")); + labelEdgesLCD->setToolTip(tr("The total number of directed edges in the network.")); + nodesLCD=new QLCDNumber(7); nodesLCD->setSegmentStyle(QLCDNumber::Flat); - nodesLCD->setToolTip(tr("Counts how many nodes (vertices) exist in the whole network.")); + nodesLCD->setToolTip(tr("The total number of nodes (vertices) in the network.")); edgesLCD=new QLCDNumber(7); edgesLCD->setSegmentStyle(QLCDNumber::Flat); - edgesLCD->setToolTip(tr("Counts how many edges (arcs) exist in the whole network.")); + edgesLCD->setStatusTip(tr("Shows the total number of directed edges in the network.")); + edgesLCD->setToolTip(tr("The total number of directed edges in the network.")); QLabel *labelDensityLCD = new QLabel; labelDensityLCD->setText(tr("Density")); + labelDensityLCD->setToolTip(tr("The density of a network is the ratio of existing \n" + "edges to all possible edges ( n*(n-1) ) between nodes.")); densityLCD=new QLCDNumber(7); densityLCD->setSegmentStyle(QLCDNumber::Flat); - densityLCD->setToolTip(tr("The density of a network is the ratio of existing edges to all possible edges ( n*(n-1) ) between nodes.")); + densityLCD->setStatusTip(tr("Shows the network density, the ratio of existing " + "edges to all possible edges ( n*(n-1) ) between nodes.")); + densityLCD->setToolTip(tr("This is the density of the network. \n" + "The density of a network is the ratio of existing \n" + "edges to all possible edges ( n*(n-1) ) between nodes.")); //create a grid layout QGridLayout *propertiesGrid = new QGridLayout(); - propertiesGrid -> setColumnMinimumWidth(0, 10); propertiesGrid -> setColumnMinimumWidth(1, 10); - propertiesGrid -> addWidget(labelNodesLCD, 0,0); - propertiesGrid -> addWidget(labelEdgesLCD, 0,1); - propertiesGrid -> addWidget(nodesLCD,1,0); - propertiesGrid -> addWidget(edgesLCD,1,1); - - propertiesGrid -> addWidget(labelDensityLCD, 2,0); - propertiesGrid -> addWidget(densityLCD,2,1); + networkLabel = new QLabel; + networkLabel-> setText ("Network Type: Undirected"); + networkLabel->setStatusTip(tr("Directed data mode. Toggle the menu option Edit -> Edges -> Undirected Edges to change it")); + + networkLabel->setToolTip(tr("The loaded network, if any, is directed and \n" + "any link you add between nodes will be a directed arc.\n" + "If you want to work with undirected edges and/or \n" + "transform the loaded network (if any) to undirected \n" + "toggle the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + networkLabel->setWhatsThis(tr("The loaded network, if any, is directed and \n" + "any link you add between nodes will be a directed arc.\n" + "If you want to work with undirected edges and/or \n" + "transform the loaded network (if any) to undirected \n" + "toggle the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + + QFont labelFont = networkLabel ->font(); + labelFont.setWeight(QFont::Bold); + networkLabel ->setFont(labelFont); + networkLabel ->setFixedWidth(195); + propertiesGrid -> addWidget(networkLabel , 0,0); + propertiesGrid -> addWidget(labelNodesLCD, 1,0); + propertiesGrid -> addWidget(nodesLCD,1,1); + propertiesGrid -> addWidget(labelEdgesLCD, 2,0); + propertiesGrid -> addWidget(edgesLCD,2,1); + propertiesGrid -> addWidget(labelDensityLCD, 3,0); + propertiesGrid -> addWidget(densityLCD,3,1); QLabel *dummyLabel = new QLabel; - dummyLabel-> setText (" "); + dummyLabel-> setText (""); QLabel *labelNode = new QLabel; labelNode-> setText (tr("Active Node")); - labelNode ->setFont(QFont("sans-serif", 10, QFont::Bold)); + labelNode->setFont(labelFont); QLabel *labelSelectedNodeLCD = new QLabel; - labelSelectedNodeLCD -> setText (tr("Node Number:")); + labelSelectedNodeLCD -> setText (tr("Number:")); labelSelectedNodeLCD -> setToolTip (tr("This is the number of the last selected node.")); - selectedNodeLCD =new QLCDNumber(7); + selectedNodeLCD =new QLCDNumber(5); selectedNodeLCD ->setSegmentStyle(QLCDNumber::Flat); QLabel *labelInDegreeLCD = new QLabel; - labelInDegreeLCD -> setText (tr("Node In-Degree:")); - labelInDegreeLCD -> setToolTip (tr("The sum of all in-edge weights of the node you clicked..")); - inDegreeLCD=new QLCDNumber(7); + labelInDegreeLCD -> setText (tr("In-Degree:")); + labelInDegreeLCD -> setToolTip (tr("The inDegree of a node is the sum of all inbound edge weights.")); + inDegreeLCD=new QLCDNumber(5); inDegreeLCD -> setSegmentStyle(QLCDNumber::Flat); - inDegreeLCD -> setToolTip (tr("The sum of all in-edge weights of the node you clicked.")); + inDegreeLCD -> setToolTip (tr("The sum of all inbound edge weights of the node you clicked.")); + inDegreeLCD -> setStatusTip (tr("The sum of all inbound edge weights of the node you clicked.")); QLabel *labelOutDegreeLCD = new QLabel; - labelOutDegreeLCD -> setText (tr("Node Out-Degree:")); - labelOutDegreeLCD -> setToolTip (tr("The sum of all out-edge weights of the node you clicked.")); - outDegreeLCD=new QLCDNumber(7); + labelOutDegreeLCD -> setText (tr("Out-Degree:")); + labelOutDegreeLCD -> setToolTip (tr("The outDegree of a node is the sum of all outbound edge weights.")); + outDegreeLCD=new QLCDNumber(5); outDegreeLCD -> setSegmentStyle(QLCDNumber::Flat); - outDegreeLCD -> setToolTip (tr("The sum of all out-edge weights of the node you clicked.")); + outDegreeLCD -> setStatusTip (tr("The sum of all outbound edge weights of the node you clicked.")); + outDegreeLCD -> setToolTip (tr("The sum of all outbound edge weights of the node you clicked.")); QLabel *labelClucofLCD = new QLabel; - labelClucofLCD -> setText (tr("Clustering Coef.")); - labelClucofLCD -> setToolTip (tr("The Clustering Coefficient quantifies how close the clicked vertex and its neighbors are to being a clique. \nThe value is the proportion of Edges between the vertices within the neighbourhood of the clicked vertex,\n divided by the number of Edges that could possibly exist between them. \n\n WARNING: This value is automatically calculated only if vertices < 500.\n If your network is larger than 500 vertices, compute CluCof from the menu Analysis > Clustering Coefficient ")); - clucofLCD = new QLCDNumber(7); + labelClucofLCD -> setText (tr("Clu.Coef.")); + labelClucofLCD -> setWhatsThis( + tr("The Clustering Coefficient quantifies how close the clicked \n" + "vertex and its neighbors are to being a clique. \n" + "The value is the proportion of Edges between the vertices \n" + "within the neighbourhood of the clicked vertex, \n" + "divided by the number of Edges that could possibly exist " + "between them. \n\n " + "This value is automatically calculated only if vertices < 500.\n" + "If your network is larger than 500 vertices, compute CluCof " + "from the menu Analysis > Clustering Coefficient ")); + labelClucofLCD -> setToolTip ( + tr("The Clustering Coefficient quantifies how close the clicked \n" + "vertex and its neighbors are to being a clique. \n" + "The value is the proportion of Edges between the vertices \n" + "within the neighbourhood of the clicked vertex, \n" + "divided by the number of Edges that could possibly exist " + "between them. \n\n " + "This value is automatically calculated only if vertices < 500.\n" + "If your network is larger than 500 vertices, compute CluCof " + "from the menu Analysis > Clustering Coefficient ")); + clucofLCD = new QLCDNumber(5); clucofLCD -> setSegmentStyle(QLCDNumber::Flat); - clucofLCD -> setToolTip (tr("The Clustering Coefficient quantifies how close the clicked vertex and its neighbors are to being a clique. \nThe value is the proportion of Edges between the vertices within the neighbourhood of the clicked vertex,\n divided by the number of Edges that could possibly exist between them. \n\n This value is automatically calculated only if vertices < 500.\n If your network is larger than 500 vertices, compute CluCof from the menu Analysis > Clustering Coefficient ")); + clucofLCD -> setStatusTip( tr("The Clustering Coefficient of the active node.")); + clucofLCD -> setWhatsThis( + tr("The Clustering Coefficient of the active node. \n" + "The Clustering Coefficient quantifies how close the clicked \n" + "vertex and its neighbors are to being a clique. \n" + "The value is the proportion of Edges between the vertices \n" + "within the neighbourhood of the clicked vertex, \n" + "divided by the number of Edges that could possibly exist " + "between them. \n\n " + "This value is automatically calculated only if vertices < 500.\n" + "If your network is larger than 500 vertices, compute CluCof " + "from the menu Analysis > Clustering Coefficient ")); + clucofLCD -> setToolTip ( + tr("The Clustering Coefficient of the active node. \n" + "The Clustering Coefficient quantifies how close the clicked \n" + "vertex and its neighbors are to being a clique. \n" + "The value is the proportion of Edges between the vertices \n" + "within the neighbourhood of the clicked vertex, \n" + "divided by the number of Edges that could possibly exist " + "between them. \n\n " + "This value is automatically calculated only if vertices < 500.\n" + "If your network is larger than 500 vertices, compute CluCof " + "from the menu Analysis > Clustering Coefficient ")); propertiesGrid -> addWidget(dummyLabel, 6,0); @@ -2454,297 +3024,533 @@ void MainWindow::initToolBox(){ propertiesGrid -> addWidget(clucofLCD,11,1); propertiesGrid -> setRowStretch(12,1); //fix stretch - //create a box with title - QGroupBox *networkPropertiesGroup = new QGroupBox(tr("")); - networkPropertiesGroup -> setLayout (propertiesGrid); + //create a panel with title + rightPanel = new QGroupBox(tr("Statistics Panel")); + rightPanel->setMaximumWidth(210); + rightPanel -> setLayout (propertiesGrid); +} - toolBox->addTab( networkPropertiesGroup, tr("Statistics")); - toolBox->setMinimumWidth(controlGroupBox->sizeHint().width()); - toolBox->setFixedWidth(300); - //toolBox->setStyleSheet("* { background-color:#ededed}}"); -} -//Called from MW, when user selects something in the Geodesics selectbox -// of toolbox -void MainWindow::toolBoxAnalysisGeodesicsSelectChanged(int selectedIndex) { - qDebug()<< "MW::toolBoxAnalysisGeodesicsSelectChanged " - "selected text index: " << selectedIndex; - switch(selectedIndex){ - case 0: - break; - case 1: - slotGraphDistance(); - break; - case 2: - slotAverageGraphDistance(); - break; - case 3: - slotDistancesMatrix(); - break; - case 4: - slotGeodesicsMatrix(); - break; - case 5: - slotEccentricity(); - break; - case 6: - slotDiameter(); - break; - }; + + + +/** + * @brief MainWindow::initStatusBar + * Initializes the status bar + */ +void MainWindow::initStatusBar() { + statusBarDuration=3000; + statusMessage( tr("Ready.")); } -//Called from MW, when user selects something in the Connectivity selectbox -// of toolbox -void MainWindow::toolBoxAnalysisConnectivitySelectChanged(int selectedIndex) { - qDebug()<< "MW::toolBoxAnalysisConnectivitySelectChanged " - "selected text index: " << selectedIndex; - switch(selectedIndex){ - case 0: - break; - case 1: - qDebug()<< "Connectedness"; - slotConnectedness(); - break; - case 2: - qDebug()<< "Walks of given length"; - slotWalksOfGivenLength(); - break; - case 3: - qDebug() << "Total Walks selected"; - slotTotalWalks(); - break; - case 4: - qDebug() << "Reachability Matrix"; - slotReachabilityMatrix(); - break; - }; -} +/** + * @brief MainWindow::initView + * Initializes the scene and the corresponding graphicsWidget, + * The latter is a QGraphicsView canvas which is the main widget of SocNetV. + */ +void MainWindow::initView() { + qDebug ()<< "MW::initView()"; + //create a scene + scene=new QGraphicsScene(); + //create a view widget for this scene + graphicsWidget=new GraphicsWidget(scene, this); + graphicsWidget->setViewportUpdateMode( QGraphicsView::SmartViewportUpdate ); + // FullViewportUpdate // MinimalViewportUpdate //SmartViewportUpdate //BoundingRectViewportUpdate + //QGraphicsView can cache pre-rendered content in a QPixmap, which is then drawn onto the viewport. + graphicsWidget->setCacheMode(QGraphicsView::CacheNone); //CacheBackground | CacheNone + bool antialiasing = (appSettings["antialiasing"] == "true" ) ? true:false; + graphicsWidget->setRenderHint(QPainter::Antialiasing, antialiasing ); + graphicsWidget->setRenderHint( + QPainter::TextAntialiasing, antialiasing ); + graphicsWidget->setRenderHint(QPainter::SmoothPixmapTransform, antialiasing ); + //Optimization flags: + //if items do restore their state, it's not needed for graphicsWidget to do the same... + graphicsWidget->setOptimizationFlag(QGraphicsView::DontSavePainterState, true); + //Disables QGraphicsView's antialiasing auto-adjustment of exposed areas. + graphicsWidget->setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, false); + //"QGraphicsScene applies an indexing algorithm to the scene, to speed up item discovery functions like items() and itemAt(). + // Indexing is most efficient for static scenes (i.e., where items don't move around). + // For dynamic scenes, or scenes with many animated items, the index bookkeeping can outweight the fast lookup speeds." So... + scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex); //NoIndex (for anime) | BspTreeIndex -//Called from MW, when user selects something in the Clusterability selectbox -// of toolbox -void MainWindow::toolBoxAnalysisClusterabilitySelectChanged(int selectedIndex) { - qDebug()<< "MW::toolBoxAnalysisClusterabilitySelectChanged " - "selected text index: " << selectedIndex; - switch(selectedIndex){ - case 0: - break; - case 1: - qDebug()<< "Cliques"; - slotCliqueCensus(); - break; - case 2: - qDebug()<< "Clustering Coefficient"; - slotClusteringCoefficient(); - break; - case 3: - qDebug() << "Triad Census"; - slotTriadCensus(); - break; + graphicsWidget->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); + //graphicsWidget->setTransformationAnchor(QGraphicsView::AnchorViewCenter); + //graphicsWidget->setTransformationAnchor(QGraphicsView::NoAnchor); + graphicsWidget->setResizeAnchor(QGraphicsView::AnchorViewCenter); - }; + // sets dragging the mouse over the scene while the left mouse button is pressed. + graphicsWidget->setDragMode(QGraphicsView::RubberBandDrag); + graphicsWidget->setFocusPolicy(Qt::StrongFocus); + graphicsWidget->setFocus(); + graphicsWidget->setWhatsThis(tr("The canvas of SocNetV. \n\n" + "Inside this area you create and edit networks, " + "load networks from files and visualize them \n" + "according to selected metrics. \n\n" + " - To create a new node, double-click anywhere (Ctrl+.)\n" + " - To add an arc between two nodes, double-click" + " on the first node then double-click on the second (Ctrl+/)\n" + " - To change network appearance, right click on empty space\n" + " - To change/edit the properties of a node, right-click on it\n" + " - To change/edit the properties of an edge, right-click on it." + "")); } -//Called from MW, when user selects something in the Prominence selectbox -// of toolbox -void MainWindow::toolBoxAnalysisProminenceSelectChanged(int selectedIndex) { - qDebug()<< "MW::toolBoxAnalysisProminenceSelectChanged " - "selected text index: " << selectedIndex; - switch(selectedIndex){ - case 0: - break; - case 1: - slotCentralityDegree(); - break; - case 2: - slotCentralityCloseness(); - break; - case 3: - slotCentralityClosenessInfluenceRange(); - break; - case 4: - slotCentralityBetweenness(); - break; - case 5: - slotCentralityStress(); - break; - case 6: - slotCentralityEccentricity(); - break; - case 7: - slotCentralityPower(); - break; - case 8: - slotCentralityInformation(); - break; - case 9: - slotPrestigeDegree(); - break; - case 10: - slotPrestigePageRank(); - break; - case 11: - slotPrestigeProximity(); - break; - }; +/** + * @brief MainWindow::initWindowLayout + * Initializes the application window UI: + * Creates helper widgets and sets the main layout of the MainWindow + */ +void MainWindow::initWindowLayout() { + qDebug () << "MW::initWindowLayout"; + int size = style()->pixelMetric(QStyle::PM_ToolBarIconSize); + QSize iconSize(size, size); + iconSize.setHeight(16); + iconSize.setWidth(16); + // Zoom slider + zoomInBtn = new QToolButton; + zoomInBtn->setShortcut(Qt::CTRL + Qt::Key_Plus); + zoomInBtn->setToolTip(tr("Zoom in (Ctrl++)")); + zoomInBtn->setStatusTip(tr("Zoom inside the actual network. Or press Cltr and use mouse wheel.")); + zoomInBtn->setWhatsThis(tr("Zoom In.\n\n" + "Zooms in the actual network" + "You can also press Cltr and use mouse wheel.")); + zoomInBtn->setAutoRepeat(true); + zoomInBtn->setAutoRepeatInterval(33); + zoomInBtn->setAutoRepeatDelay(0); + zoomInBtn->setIcon(QPixmap(":/images/zoomin.png")); + zoomInBtn->setIconSize(iconSize); + + zoomOutBtn = new QToolButton; + zoomOutBtn->setAutoRepeat(true); + zoomOutBtn->setShortcut(Qt::CTRL + Qt::Key_Minus); + zoomOutBtn->setToolTip(tr("Zoom out (Ctrl+-)")); + zoomOutBtn->setStatusTip(tr("Zoom out of the actual network. Or press Cltr and use mouse wheel.")); + zoomOutBtn->setWhatsThis(tr("Zoom out.\n\n" + "Zooms out the actual network" + "You can also press Cltr and use mouse wheel.")); + zoomOutBtn->setAutoRepeat(true); + zoomOutBtn->setAutoRepeatInterval(33); + zoomOutBtn->setAutoRepeatDelay(0); + zoomOutBtn->setIcon(QPixmap(":/images/zoomout.png")); + zoomOutBtn->setIconSize(iconSize); + + zoomSlider = new QSlider; + zoomSlider->setMinimum(0); + zoomSlider->setMaximum(500); + zoomSlider->setValue(250); + zoomSlider->setToolTip(tr("Zoom slider: Drag up to zoom in. \n" + "Drag down to zoom out. ")); + zoomSlider->setWhatsThis(tr("Zoom slider: Drag up to zoom in. \n" + "Drag down to zoom out. ")); + zoomSlider->setTickPosition(QSlider::TicksBothSides); + + // Zoom slider layout + QVBoxLayout *zoomSliderLayout = new QVBoxLayout; + zoomSliderLayout->addWidget(zoomInBtn); + zoomSliderLayout->addWidget(zoomSlider); + zoomSliderLayout->addWidget(zoomOutBtn); + + // Rotate slider + rotateLeftBtn = new QToolButton; + rotateLeftBtn->setAutoRepeat(true); + rotateLeftBtn->setShortcut(Qt::CTRL + Qt::Key_Left); + rotateLeftBtn->setIcon(QPixmap(":/images/rotateleft.png")); + rotateLeftBtn->setToolTip(tr("Rotate counterclockwise (Ctrl+Left Arrow)")); + rotateLeftBtn->setStatusTip(tr("Rotate counterclockwise (Ctrl+Left Arrow)")); + rotateLeftBtn->setWhatsThis(tr("Rotates counterclockwise (Ctrl+Left Arrow)")); + rotateLeftBtn->setIconSize(iconSize); + + rotateRightBtn = new QToolButton; + rotateRightBtn->setAutoRepeat(true); + rotateRightBtn->setShortcut(Qt::CTRL + Qt::Key_Right); + rotateRightBtn ->setIcon(QPixmap(":/images/rotateright.png")); + rotateRightBtn->setToolTip(tr("Rotate clockwise (Ctrl+Right Arrow)")); + rotateRightBtn->setStatusTip(tr("Rotate clockwise (Ctrl+Right Arrow)")); + rotateRightBtn->setWhatsThis(tr("Rotates clockwise (Ctrl+Right Arrow)")); + rotateRightBtn ->setIconSize(iconSize); + + rotateSlider = new QSlider; + rotateSlider->setOrientation(Qt::Horizontal); + rotateSlider->setMinimum(-180); + rotateSlider->setMaximum(180); + rotateSlider->setTickInterval(5); + rotateSlider->setValue(0); + rotateSlider->setToolTip(tr("Rotate slider: Drag to left to rotate clockwise. \n" + "Drag to right to rotate counterclockwise. ")); + rotateSlider->setWhatsThis(tr("Rotate slider: Drag to left to rotate clockwise. " + "Drag to right to rotate counterclockwise. ")); + rotateSlider->setTickPosition(QSlider::TicksBothSides); + + // Rotate slider layout + QHBoxLayout *rotateSliderLayout = new QHBoxLayout; + rotateSliderLayout->addWidget(rotateLeftBtn); + rotateSliderLayout->addWidget(rotateSlider); + rotateSliderLayout->addWidget(rotateRightBtn ); + + resetSlidersBtn = new QToolButton; + resetSlidersBtn->setText(tr("Reset")); + resetSlidersBtn->setShortcut(Qt::CTRL + Qt::Key_0); + resetSlidersBtn->setToolTip(tr("Reset zoom and rotation to zero (Ctrl+0)")); + resetSlidersBtn->setWhatsThis(tr("Reset zoom and rotation to zero (Ctrl+0)")); + resetSlidersBtn->setIcon(QPixmap(":/images/reset.png")); + resetSlidersBtn ->setIconSize(iconSize); + resetSlidersBtn->setEnabled(true); + + // Create a layout for the toolbox and the canvas. + // This will be the layout of our MW central widget + QGridLayout *layout = new QGridLayout; + layout->addWidget(leftPanel, 0, 0, 2,1); + layout->addWidget(graphicsWidget,0,1); + layout->addLayout(zoomSliderLayout, 0, 2); + layout->addWidget(rightPanel, 0, 3,2,1); + layout->addLayout(rotateSliderLayout, 1, 1, 1, 1); + layout->addWidget(resetSlidersBtn, 1, 2, 1, 1); + + //create a dummy widget, and set the above layout + QWidget *widget = new QWidget; + widget->setLayout(layout); + //now set this as central widget of MW + setCentralWidget(widget); -} + // set panels visibility + if ( appSettings["showRightPanel"] == "false") { + slotOptionsRightPanelVisibility(false); + } -void MainWindow::toolBoxLayoutByIndexButtonPressed(){ - qDebug()<<"MW::toolBoxLayoutByIndexButtonPressed()"; - int selectedIndex = toolBoxLayoutByIndexSelect->currentIndex(); - QString selectedIndexText = toolBoxLayoutByIndexSelect -> currentText(); - int selectedLayoutType = toolBoxLayoutByIndexTypeSelect ->currentIndex(); - qDebug() << " selected index is " << selectedIndexText << " : " << selectedIndex - << " selected layout type is " << selectedLayoutType; - switch(selectedIndex) { - case 0: - break; - case 1: - if (selectedLayoutType==0) - slotLayoutCircularRandom(); - else if (selectedLayoutType==1) - slotLayoutRandom(); - break; - default: - if (selectedLayoutType==0) - slotLayoutCircularByProminenceIndex(selectedIndexText); - else if (selectedLayoutType==1) - slotLayoutLevelByProminenceIndex(selectedIndexText); - else if (selectedLayoutType==2){ - slotLayoutNodeSizesByProminenceIndex(selectedIndexText); - // re-init other options for node sizes... - nodeSizesByOutDegreeAct->setChecked(false); - nodeSizesByOutDegreeBx->setChecked(false); - nodeSizesByInDegreeAct->setChecked(false); - nodeSizesByInDegreeBx->setChecked(false); - } - break; - }; -} + if ( appSettings["showLeftPanel"] == "false") { + slotOptionsLeftPanelVisibility(false); + } + qDebug () << "MW::initWindowLayout - resize to 1280x900"; + this->resize(1280,900); + + this->showMaximized(); -//FIXME this is a bug: Graph calls GraphicsWidget which calls this to call Graph! -void MainWindow::updateNodeCoords(int nodeNumber, int x, int y){ - // qDebug("MW: updateNodeCoords() for %i with x %i and y %i", nodeNumber, x, y); - activeGraph.updateVertCoords(nodeNumber, x, y); } + + + + /** - Initializes the status bar -*/ -void MainWindow::initStatusBar() { - statusBarDuration=3000; - statusMessage( tr("Ready.")); -} + * @brief MainWindow::initSignalSlots + * Connect signals & slots between various parts of the app: + * - the GraphicsWidget and the Graph + * - the GraphicsWidget and the MainWindow + * This must be called after all widgets have been created. + * + */ +void MainWindow::initSignalSlots() { + qDebug ()<< "MW::initSignalSlots()"; + // Signals from graphicsWidget to MainWindow + connect( graphicsWidget, SIGNAL( resized(int, int)), + &activeGraph, SLOT( canvasSizeSet(int,int)) ) ; + connect( graphicsWidget, SIGNAL( selectedNode(Node*) ), + this, SLOT( nodeInfoStatusBar(Node*) ) ); + connect( graphicsWidget, SIGNAL( selectedEdge(Edge*) ), + this, SLOT ( edgeInfoStatusBar(Edge*) ) ); + connect( graphicsWidget, SIGNAL( userClickOnEmptySpace() ), + this, SLOT( slotEditClickOnEmptySpace() ) ) ; + connect( graphicsWidget, SIGNAL( + userDoubleClickNewNode(const QPointF &) ), + this, SLOT( + slotEditNodeAddWithMouse(const QPointF &) ) ) ; -/** - Initializes the scene and its graphicsWidget, the main widget of SocNetV -*/ -void MainWindow::initView() { - qDebug ("MW initView()"); - //create a scene - scene=new QGraphicsScene(); + connect( graphicsWidget, SIGNAL( userMiddleClicked(const int &, const int &, const float&) ), + this, SLOT( slotEditEdgeCreate(int, int, float) ) ); - //create a view widget for this scene - graphicsWidget=new GraphicsWidget(scene, this); - graphicsWidget->setViewportUpdateMode( QGraphicsView::BoundingRectViewportUpdate ); - // FullViewportUpdate // MinimalViewportUpdate //SmartViewportUpdate //BoundingRectViewportUpdate - //QGraphicsView can cache pre-rendered content in a QPixmap, which is then drawn onto the viewport. - graphicsWidget->setCacheMode(QGraphicsView::CacheNone); //CacheBackground | CacheNone - graphicsWidget->setRenderHint(QPainter::Antialiasing, true); - graphicsWidget->setRenderHint(QPainter::TextAntialiasing, true); - graphicsWidget->setRenderHint(QPainter::SmoothPixmapTransform, true); - //Optimization flags: - //if items do restore their state, it's not needed for graphicsWidget to do the same... - graphicsWidget->setOptimizationFlag(QGraphicsView::DontSavePainterState, false); - //Disables QGraphicsView's antialiasing auto-adjustment of exposed areas. - graphicsWidget->setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, false); - //"QGraphicsScene applies an indexing algorithm to the scene, to speed up item discovery functions like items() and itemAt(). - // Indexing is most efficient for static scenes (i.e., where items don't move around). - // For dynamic scenes, or scenes with many animated items, the index bookkeeping can outweight the fast lookup speeds." So... - scene->setItemIndexMethod(QGraphicsScene::BspTreeIndex); //NoIndex (for anime) | BspTreeIndex + connect( graphicsWidget, SIGNAL( openNodeMenu() ), + this, SLOT( slotEditNodeOpenContextMenu() ) ) ; - graphicsWidget->setTransformationAnchor(QGraphicsView::AnchorUnderMouse); - graphicsWidget->setResizeAnchor(QGraphicsView::AnchorViewCenter); + connect( graphicsWidget, SIGNAL( openEdgeMenu() ), + this, SLOT( openEdgeContextMenu() ) ) ; - // sets dragging the mouse over the scene while the left mouse button is pressed. - graphicsWidget->setDragMode(QGraphicsView::RubberBandDrag); - graphicsWidget->setFocusPolicy(Qt::StrongFocus); - graphicsWidget->setFocus(); + connect (graphicsWidget, &GraphicsWidget::openContextMenu, + this, &MainWindow::slotEditOpenContextMenu); - this->resize(1280,900); + connect( graphicsWidget, SIGNAL(updateNodeCoords(const int &, const int &, const int &)), + this, SLOT( updateNodeCoords(const int &, const int &, const int &) ) ); - //set minimum size of canvas - graphicsWidget->setMinimumSize( (qreal) ( this->width()-toolBox->sizeHint().width() -40 ) , (qreal) ( this->height()-statusBar()->sizeHint().height() -toolBar->sizeHint().height() -menuBar()->sizeHint().height() -20 ) ); - qDebug ("MW initView(): now window size %i, %i, graphicsWidget size %i, %i, scene %f,%f",this->width(),this->height(), graphicsWidget->width(),graphicsWidget->height(), graphicsWidget->scene()->width(), graphicsWidget->scene()->height()); + connect( graphicsWidget, SIGNAL(zoomChanged(const int &)), + zoomSlider, SLOT( setValue(const int &)) ); -} + connect(zoomSlider, SIGNAL(valueChanged(const int &)), + graphicsWidget, SLOT(changeMatrixScale(const int &))); + connect( zoomInBtn, SIGNAL(clicked()), graphicsWidget, SLOT( zoomIn() ) ); + connect( zoomOutBtn, SIGNAL(clicked()), graphicsWidget, SLOT( zoomOut() ) ); + connect( graphicsWidget, SIGNAL(rotationChanged(const int &)), + rotateSlider, SLOT( setValue(const int &)) ); + connect(rotateSlider, SIGNAL(valueChanged(const int &)), + graphicsWidget, SLOT(changeMatrixRotation(const int &))); + + connect(rotateLeftBtn, SIGNAL(clicked()), graphicsWidget, SLOT(rotateLeft())); + connect(rotateRightBtn, SIGNAL(clicked()), graphicsWidget, SLOT(rotateRight())); + + connect(resetSlidersBtn, SIGNAL(clicked()), graphicsWidget, SLOT(reset())); + + + // Signals from activeGraph to graphicsWidget + connect( &activeGraph, + SIGNAL( addGuideCircle(const double&, const double&, const double&) ), + graphicsWidget, + SLOT( addGuideCircle(const double&, const double&, const double&) ) ) ; + + connect( &activeGraph, SIGNAL( addGuideHLine(const double&) ), + graphicsWidget, SLOT( addGuideHLine(const double&) ) ) ; + + connect( &activeGraph, SIGNAL( moveNode(const int &, const qreal &, const qreal &) ), + graphicsWidget, SLOT( moveNode(const int &, const qreal &, const qreal &) ) ) ; -/** - Resizes the scene when the window is resized. -*/ -void MainWindow::resizeEvent( QResizeEvent * ){ - qDebug ("MW resizeEvent():INITIAL window size %i, %i, graphicsWidget size %i, %i, scene %f,%f",this->width(),this->height(), graphicsWidget->width(),graphicsWidget->height(), graphicsWidget->scene()->width(), graphicsWidget->scene()->height()); - //the area of the scene displayed by the CanvasView - scene->setSceneRect(0, 0, (qreal) ( graphicsWidget->width() -5 ), (qreal) (graphicsWidget->height() -5 ) ); - qDebug ("MW resizeEvent(): now window size %i, %i, graphicsWidget size %i, %i, scene %f,%f",this->width(),this->height(), graphicsWidget->width(),graphicsWidget->height(), graphicsWidget->scene()->width(), graphicsWidget->scene()->height()); + + connect( &activeGraph, + SIGNAL( + drawNode( const int &, const int &, const QString &, + const QString &, + const bool &,const bool &, + const QString &, const int &, + const bool &, const QString &, + const QString &, const int &, + const QPointF & + ) + ), + graphicsWidget, + SLOT( + drawNode( const int &, const int &, const QString &, + const QString &, + const bool &,const bool &, + const QString &, const int &, + const bool &, const QString &, + const QString &, const int &, + const QPointF & + ) + ) + ) ; + + connect( &activeGraph, SIGNAL( eraseEdge(const long int &, const long int &)), + graphicsWidget, SLOT( eraseEdge(const long int &, const long int &) ) ); + + connect( &activeGraph, SIGNAL( graphChanged() ), + this, SLOT( slotNetworkChanged() ) ) ; + + connect( &activeGraph, SIGNAL( signalFileType( int, QString, + int , int, bool) ), + this, SLOT( fileType( int, QString, int , int, bool) ) ) ; + + connect( &activeGraph, SIGNAL( drawEdge( const int&, const int&, const float &, + const QString &, const QString &, + const int&, const bool&, + const bool&, + const bool&)), + graphicsWidget, SLOT( drawEdge( const int&, const int&, const float &, + const QString &,const QString &, + const int &, const bool&, + const bool &, + const bool&) ) ) ; + + + connect( &activeGraph, SIGNAL( setEdgeWeight(const long int &, + const long int &, + const float &)), + graphicsWidget, SLOT( setEdgeWeight(const long int &, + const long int &, + const float &) ) ); + + connect( &activeGraph, SIGNAL( setEdgeUndirected(const long int &, + const long int &, + const float &)), + graphicsWidget, SLOT( setEdgeUndirected(const long int &, + const long int &, + const float &) ) ); + + + + connect( &activeGraph, SIGNAL( setEdgeColor(const long int &, + const long int &, + const QString &)), + graphicsWidget, SLOT( setEdgeColor(const long int &, + const long int &, + const QString &) ) ); + + + connect( &activeGraph, SIGNAL( setEdgeLabel(const long int &, + const long int &, + const QString &)), + graphicsWidget, SLOT( setEdgeLabel(const long int &, + const long int &, + const QString &) ) ); + + + connect( &activeGraph, SIGNAL( eraseNode(long int) ), + graphicsWidget, SLOT( eraseNode(long int) ) ); + + connect( &activeGraph, SIGNAL( setEdgeVisibility (int, int, int, bool) ), + graphicsWidget, SLOT( setEdgeVisibility (int, int, int, bool) ) ); + + connect( &activeGraph, SIGNAL( setVertexVisibility(long int, bool) ), + graphicsWidget, SLOT( setNodeVisibility (long int , bool) ) ); + + connect( &activeGraph, SIGNAL( setNodeSize(const long int &, const int &) ), + graphicsWidget, SLOT( setNodeSize (const long int &, const int &) ) ); + + connect( &activeGraph, SIGNAL( setNodeColor(long int,QString)) , + graphicsWidget, SLOT( setNodeColor(long int, QString) ) ); + + connect( &activeGraph, SIGNAL( setNodeShape(long int,QString)) , + graphicsWidget, SLOT( setNodeShape(long int, QString) ) ); + + connect( &activeGraph, SIGNAL( setNodeNumberSize(const long int &, const int &) ), + graphicsWidget, SLOT( setNodeNumberSize (const long int &, const int &) ) ); + + connect( &activeGraph, SIGNAL( setNodeNumberDistance(const long int &, const int &) ), + graphicsWidget, SLOT( setNodeNumberDistance (const long int &, const int &) ) ); + + connect( &activeGraph, &Graph::setNodeLabel , + graphicsWidget, &GraphicsWidget::setNodeLabel ); + + connect( &activeGraph, SIGNAL( setNodeLabelSize(const long int &, const int &) ), + graphicsWidget, SLOT( setNodeLabelSize (const long int &, const int &) ) ); + + connect( &activeGraph, SIGNAL( setNodeLabelDistance(const long int &, const int &) ), + graphicsWidget, SLOT( setNodeLabelDistance (const long int &, const int &) ) ); + + + connect( &activeGraph, SIGNAL( statusMessage (QString) ), + this, SLOT( statusMessage (QString) ) ) ; + + connect( &activeGraph, SIGNAL( describeDataset (QString) ), + this, SLOT( showMessageToUser (QString) ) ) ; + + connect( &activeGraph, &Graph::signalNodeSizesByInDegree, + this, &MainWindow::slotLayoutNodeSizesByInDegree ); + + + + + //signals and slots inside MainWindow + connect( editNodeAddBt,SIGNAL(clicked()), this, SLOT( slotEditNodeAdd() ) ); + + connect( editEdgeAddBt,SIGNAL(clicked()), this, SLOT( slotEditEdgeAdd() ) ); + + connect( removeNodeBt,SIGNAL(clicked()), this, SLOT( slotEditNodeRemove() ) ); + + connect( editEdgeRemoveBt,SIGNAL(clicked()), this, SLOT( slotEditEdgeRemove() ) ); + + + connect( editRelationNextAct, SIGNAL(triggered()), + this, SLOT( slotEditRelationNext() ) ); + connect( editRelationPreviousAct, SIGNAL(triggered()), + this, SLOT( slotEditRelationPrev() ) ); + connect( editRelationAddAct, SIGNAL(triggered()), this, SLOT( slotEditRelationAdd() ) ); + + connect( editRelationChangeCombo , SIGNAL( currentIndexChanged(int) ) , + &activeGraph, SLOT( relationSet(int) ) ); + + connect( this , SIGNAL(addRelationToGraph(QString)), + &activeGraph, SLOT( relationAddFromUser(QString) ) ); + + connect ( &activeGraph, SIGNAL(addRelationToMW(QString)), + this, SLOT(slotEditRelationAdd(QString))); + + connect( &activeGraph, SIGNAL(relationChanged(int)), + graphicsWidget, SLOT( relationSet(int)) ) ; + + connect( &m_DialogEdgeFilterByWeight, SIGNAL( userChoices( float, bool) ), + &activeGraph, SLOT( edgeFilterByWeight (float, bool) ) ); + + + connect( &m_WebCrawlerDialog, &WebCrawlerDialog::userChoices, + this, &MainWindow::slotNetworkWebCrawler ); + + connect( &m_datasetSelectDialog, SIGNAL( userChoices( QString) ), + this, SLOT( slotNetworkDataSetRecreate(QString) ) ); + + connect( layoutGuidesAct, SIGNAL(triggered(bool)), + graphicsWidget, SLOT(slotLayoutGuides(bool))); + + connect(toolBoxAnalysisGeodesicsSelect, SIGNAL (currentIndexChanged(int) ), + this, SLOT(toolBoxAnalysisGeodesicsSelectChanged(int) ) ); + + connect(toolBoxAnalysisConnectivitySelect, SIGNAL (currentIndexChanged(int) ), + this, SLOT(toolBoxAnalysisConnectivitySelectChanged(int) ) ); + + connect(toolBoxAnalysisClusterabilitySelect, SIGNAL (currentIndexChanged(int) ), + this, SLOT(toolBoxAnalysisClusterabilitySelectChanged(int) ) ); + + connect(toolBoxAnalysisProminenceSelect, SIGNAL (currentIndexChanged(int) ), + this, SLOT(toolBoxAnalysisProminenceSelectChanged(int) ) ); + + + + connect(toolBoxNodeSizesByOutDegreeBx , SIGNAL(clicked(bool)), + this, SLOT(slotLayoutNodeSizesByOutDegree(bool))); + connect(toolBoxNodeSizesByInDegreeBx , SIGNAL(clicked(bool)), + this, SLOT(slotLayoutNodeSizesByInDegree(bool))); + + + connect(toolBoxLayoutByIndexButton, SIGNAL (clicked() ), + this, SLOT(toolBoxLayoutByIndexButtonPressed() ) ); + + connect(toolBoxLayoutForceDirectedButton, SIGNAL (clicked() ), + this, SLOT(toolBoxLayoutForceDirectedButtonPressed() ) ); + + connect( toolBoxLayoutGuidesBx, SIGNAL(clicked(bool)), + this, SLOT(slotLayoutGuides(bool))); + } + + + + + /** - Initializes the default network parameters. - Also used when erasing a network to start a new one -*/ + * @brief MainWindow::initNet + * Initializes the default network parameters. + * Used on app start and especially when erasing a network to start a new one + */ void MainWindow::initNet(){ - qDebug()<<"MW: initNet() START INITIALISATION"; + qDebug()<<"MW::initNet() - START INITIALISATION"; QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); // Init basic variables - initNodeSize=8; - initNodeColor="red"; - initEdgeColor="black"; - initLabelColor="darkblue"; - initLabelSize=7; - initNumberSize=7; - initNumberColor="black"; - initNodeShape="circle"; - initBackgroundColor="white"; //"gainsboro"; - - minDuration=3000; //dialogue duration - obsolete - maxNodes=5000; //Max nodes used by createRandomNetwork dialogues - labelDistance=8; - numberDistance=5; + + considerWeights=false; + inverseWeights=false; + askedAboutWeights=false; + + networkName=""; previous_fileName=fileName; @@ -2754,49 +3560,95 @@ void MainWindow::initNet(){ adjacencyFileLoaded=false; fileFormat = -1; initFileCodec= "UTF-8"; - checkSelectFileType = true; dotFileLoaded=false; fileLoaded=false; networkModified=false; - fileSave->setIcon(QIcon(":/images/saved.png")); - fileSave->setEnabled(true); + networkSave->setIcon(QIcon(":/images/saved.png")); + networkSave->setEnabled(true); - markedNodesExist=false; //used by slotFindNode() + markedNodesExist=false; //used by slotEditNodeFind() cursorPosGW=QPointF(-1,-1); - clickedJimNumber=-1; + clickedNodeNumber=-1; edgeClicked=false; nodeClicked=false; - considerWeights=false; - inverseWeights=false; - askedAboutWeights=false; /** Clear previous network data */ activeGraph.clear(); activeGraph.setSocNetV_Version(VERSION); - activeGraph.setInitVertexShape(initNodeShape); - activeGraph.setInitVertexSize(initNodeSize); - activeGraph.setInitVertexColor(initNodeColor); + activeGraph.vertexShapeInit(appSettings["initNodeShape"]); + activeGraph.vertexSizeInit(appSettings["initNodeSize"].toInt(0, 10)); + activeGraph.vertexColorInit( appSettings["initNodeColor"] ); - activeGraph.setInitVertexNumberSize(initNumberSize); - activeGraph.setInitVertexNumberColor(initNumberColor); + activeGraph.vertexNumberSizeInit(appSettings["initNodeNumberSize"].toInt(0,10)); + activeGraph.vertexNumberColorInit(appSettings["initNodeNumberColor"]); - activeGraph.setInitVertexLabelColor(initLabelColor); - activeGraph.setInitVertexLabelSize(initLabelSize); + activeGraph.vertexLabelColorInit(appSettings["initNodeLabelColor"]); + activeGraph.vertexLabelSizeInit(appSettings["initNodeLabelSize"].toInt(0,10)); - activeGraph.setInitEdgeColor(initEdgeColor); + activeGraph.edgeColorInit(appSettings["initEdgeColor"]); - activeGraph.setShowLabels(this->showLabels()); - activeGraph.setShowNumbersInsideNodes( this->showNumbersInsideNodes()); + activeGraph.vertexLabelsVisibilitySet( + (appSettings["initNodeLabelsVisibility"] == "true" ) ? true: false + ); + activeGraph.vertexNumbersVisibilitySet( + ( appSettings["initNodeNumbersVisibility"] == "true" ) ? true: false + ); + activeGraph.vertexNumbersInsideNodesSet( + ( appSettings["initNodeNumbersInside"] == "true" ) ? true: false + ); - /** Clear scene **/ + /** Clear graphicsWidget scene and reset transformations **/ graphicsWidget->clear(); + rotateSlider->setValue(0); + zoomSlider->setValue(250); /** Clear LCDs **/ nodesLCD->display(activeGraph.vertices()); + if (activeGraph.isUndirected()) { + editEdgeUndirectedAllAct->setChecked(true); + edgesLCD->setStatusTip(tr("Shows the total number of undirected edges in the network.")); + edgesLCD->setToolTip(tr("The total number of undirected edges in the network.")); + networkLabel->setStatusTip(tr("Undirected data mode. Toggle the menu option Edit -> Edges -> Undirected Edges to change it")); + networkLabel->setToolTip(tr("The loaded network, if any, is undirected and \n" + "any edge you add between nodes will be undirected.\n" + "If you want to work with directed edges and/or \n" + "transform the loaded network (if any) to directed \n" + "disable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + networkLabel->setWhatsThis(tr("The loaded network, if any, is undirected and \n" + "any edge you add between nodes will be undirected.\n" + "If you want to work with directed edges and/or \n" + "transform the loaded network (if any) to directed \n" + "disable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + networkLabel-> setText ("Network Type: Undirected"); + labelEdgesLCD->setText(tr("Total Edges")); + } + else { + editEdgeUndirectedAllAct->setChecked(false); + edgesLCD->setStatusTip(tr("Shows the total number of directed edges in the network.")); + edgesLCD->setToolTip(tr("The total number of directed edges in the network.")); + networkLabel->setStatusTip(tr("Directed data mode. Toggle the menu option Edit -> Edges -> Undirected Edges to change it")); + networkLabel->setToolTip(tr("The loaded network, if any, is directed and \n" + "any link you add between nodes will be a directed arc.\n" + "If you want to work with undirected edges and/or \n" + "transform the loaded network (if any) to undirected \n" + "enable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + networkLabel->setWhatsThis(tr("The loaded network, if any, is directed and \n" + "any link you add between nodes will be a directed arc.\n" + "If you want to work with undirected edges and/or \n" + "transform the loaded network (if any) to undirected \n" + "enable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + + networkLabel-> setText ("Network Type: Directed"); + labelEdgesLCD->setText(tr("Total Arcs")); + } edgesLCD->display(activeEdges()); densityLCD->display(activeGraph.density()); inDegreeLCD->display(0); @@ -2811,47 +3663,99 @@ void MainWindow::initNet(){ toolBoxAnalysisProminenceSelect->setCurrentIndex(0); toolBoxLayoutByIndexSelect->setCurrentIndex(0); toolBoxLayoutByIndexTypeSelect ->setCurrentIndex(0); - nodeSizesByOutDegreeBx->setChecked(false); - nodeSizesByInDegreeBx->setChecked(false); - layoutEadesBx->setChecked(false); - springLayoutAct->setChecked(false); - FRLayoutAct->setChecked(false); - displayEdgesWeightNumbersAct->setChecked(false); + toolBoxLayoutForceDirectedSelect->setCurrentIndex(0); + toolBoxNodeSizesByOutDegreeBx->setChecked(false); + toolBoxNodeSizesByInDegreeBx->setChecked(false); + + optionsEdgeWeightNumbersAct->setChecked( + (appSettings["initEdgeWeightNumbersVisibility"] == "true") ? true:false + ); considerEdgeWeightsAct->setChecked(false); - //displayEdgesArrowsAct->setChecked(false); //FIXME: USER PREFS EMITTED TO GRAPH? + optionsEdgeArrowsAct->setChecked( + (appSettings["initEdgeArrows"] == "true") ? true: false + ); + optionsEdgeLabelsAct->setChecked ( + (appSettings["initEdgeLabelsVisibility"] == "true") ? true: false + + ); filterIsolateNodesAct->setChecked(false); // re-init orphan nodes menu item - changeRelationCombo->clear(); + editRelationChangeCombo->clear(); + + graphicsWidget->setInitNodeColor(appSettings["initNodeColor"]); + graphicsWidget->setInitNumberDistance( + appSettings["initNodeNumberDistance"].toInt(0,10) + ); + graphicsWidget->setInitLabelDistance( + appSettings["initNodeLabelDistance"].toInt(0,10) + ); + graphicsWidget->setInitZoomIndex(250); + graphicsWidget->setInitNodeSize(appSettings["initNodeSize"].toInt(0, 10)); + + if (appSettings["initBackgroundImage"] != "" + && QFileInfo(appSettings["initBackgroundImage"]).exists()) { + graphicsWidget->setBackgroundBrush(QImage(appSettings["initBackgroundImage"])); + graphicsWidget->setCacheMode(QGraphicsView::CacheBackground); + statusMessage( tr("BackgroundImage on.") ); + } + else { + graphicsWidget->setBackgroundBrush( + QBrush(QColor (appSettings["initBackgroundColor"])) + ); //Qt::gray + } + + - /** set window title **/ - setWindowTitle(tr("Social Network Visualizer ")+VERSION); + + /** set window title **/ + setWindowTitle(tr("Social Network Visualizer ")+VERSION); QApplication::restoreOverrideCursor(); statusMessage( tr("Ready")); qDebug("MW: initNet() INITIALISATION END"); -// QTextStream stream(stdout); -// Matrix m(10,10); -// stream << "(9,1) = " << m[9][1] ; -// m[9][1]=1212; -// stream<< m; +} + -// stream << "(9,1) = " << m[9][1] ; -} +void MainWindow::slotNetworkFileRecentUpdateActions() { + + int numRecentFiles = qMin(recentFiles.size(), (int)MaxRecentFiles); + + for (int i = 0; i < numRecentFiles; ++i) { + QString text = tr("&%1 %2").arg(i + 1).arg(QFileInfo(recentFiles[i]).fileName()); + recentFileActs[i]->setText(text); + recentFileActs[i]->setData(recentFiles[i]); + recentFileActs[i]->setVisible(true); + } + for (int j = numRecentFiles; j < MaxRecentFiles; ++j) + recentFileActs[j]->setVisible(false); + + //separatorAct->setVisible(numRecentFiles > 0); +} -/* +/** + * @brief MainWindow::statusMessage + * @param message + * Convenience method to show a message in the status bar, with the given duration * Slot called by Graph::statusMessage to display some message to the user */ void MainWindow::statusMessage(const QString message){ statusBar()->showMessage( message, statusBarDuration ); } + + +/** + * @brief MainWindow::showMessageToUser + * Convenience method + * @param message + */ void MainWindow::showMessageToUser(const QString message) { QMessageBox::information(this, tr("Info"), message, @@ -2859,19 +3763,284 @@ void MainWindow::showMessageToUser(const QString message) { } + + /** -* Displays a message on the status bar when you resize the window. -*/ -void MainWindow::windowInfoStatusBar(int w, int h){ - statusMessage( QString(tr("Window resized to (%1, %2) pixels.")).arg(w).arg(h) ); + * @brief MainWindow::updateNodeCoords + * Called from GraphicsWidget when a node moves to update vertex coordinates + * in Graph + * @param nodeNumber + * @param x + * @param y + */ +void MainWindow::updateNodeCoords(const int &nodeNumber, + const int &x, const int &y){ + // qDebug("MW: updateNodeCoords() for %i with x %i and y %i", nodeNumber, x, y); + activeGraph.vertexPosSet(nodeNumber, x, y); } + + /** - Closes the application. - Asks to write any unsaved network data. -*/ + * @brief MainWindow::toolBoxAnalysisGeodesicsSelectChanged + * Called from MW, when user selects something in the Geodesics selectbox of + * toolbox + * @param selectedIndex + */ +void MainWindow::toolBoxAnalysisGeodesicsSelectChanged(int selectedIndex) { + qDebug()<< "MW::toolBoxAnalysisGeodesicsSelectChanged " + "selected text index: " << selectedIndex; + switch(selectedIndex){ + case 0: + break; + case 1: + slotGraphDistance(); + break; + case 2: + slotAverageGraphDistance(); + break; + case 3: + slotDistancesMatrix(); + break; + case 4: + slotGeodesicsMatrix(); + break; + case 5: + slotEccentricity(); + break; + case 6: + slotDiameter(); + break; + }; + + +} + + + + + +/** + * @brief MainWindow::toolBoxAnalysisConnectivitySelectChanged + * @param selectedIndex + * Called from MW, when user selects something in the Connectivity selectbox of + * toolbox + */ +void MainWindow::toolBoxAnalysisConnectivitySelectChanged(int selectedIndex) { + qDebug()<< "MW::toolBoxAnalysisConnectivitySelectChanged " + "selected text index: " << selectedIndex; + switch(selectedIndex){ + case 0: + break; + case 1: + qDebug()<< "Connectedness"; + slotConnectedness(); + break; + case 2: + qDebug()<< "Walks of given length"; + slotWalksOfGivenLength(); + break; + case 3: + qDebug() << "Total Walks selected"; + slotTotalWalks(); + break; + case 4: + qDebug() << "Reachability Matrix"; + slotReachabilityMatrix(); + break; + }; + +} + + + + +/** + * @brief MainWindow::toolBoxAnalysisClusterabilitySelectChanged + * @param selectedIndex + * Called from MW, when user selects something in the Clusterability selectbox + * of toolbox + */ +void MainWindow::toolBoxAnalysisClusterabilitySelectChanged(int selectedIndex) { + qDebug()<< "MW::toolBoxAnalysisClusterabilitySelectChanged " + "selected text index: " << selectedIndex; + switch(selectedIndex){ + case 0: + break; + case 1: + qDebug()<< "Cliques"; + slotCliqueCensus(); + break; + case 2: + qDebug()<< "Clustering Coefficient"; + slotClusteringCoefficient(); + break; + case 3: + qDebug() << "Triad Census"; + slotTriadCensus(); + break; + }; + +} + + + + + +/** + * @brief MainWindow::toolBoxAnalysisProminenceSelectChanged + * @param selectedIndex + * Called from MW, when user selects something in the Prominence selectbox + * of toolbox + */ +void MainWindow::toolBoxAnalysisProminenceSelectChanged(int selectedIndex) { + qDebug()<< "MW::toolBoxAnalysisProminenceSelectChanged " + "selected text index: " << selectedIndex; + switch(selectedIndex){ + case 0: + break; + case 1: + slotCentralityDegree(); + break; + case 2: + slotCentralityCloseness(); + break; + case 3: + slotCentralityClosenessInfluenceRange(); + break; + case 4: + slotCentralityBetweenness(); + break; + case 5: + slotCentralityStress(); + break; + case 6: + slotCentralityEccentricity(); + break; + case 7: + slotCentralityPower(); + break; + case 8: + slotCentralityInformation(); + break; + case 9: + slotPrestigeDegree(); + break; + case 10: + slotPrestigePageRank(); + break; + case 11: + slotPrestigeProximity(); + break; + }; + +} + +/** + * @brief MainWindow::toolBoxLayoutByIndexButtonPressed + * Called from MW, when user selects an index in the Layout by index selectbox + * of the left panel. + */ +void MainWindow::toolBoxLayoutByIndexButtonPressed(){ + qDebug()<<"MW::toolBoxLayoutByIndexButtonPressed()"; + int selectedIndex = toolBoxLayoutByIndexSelect->currentIndex(); + QString selectedIndexText = toolBoxLayoutByIndexSelect -> currentText(); + int selectedLayoutType = toolBoxLayoutByIndexTypeSelect ->currentIndex(); + qDebug() << " selected index is " << selectedIndexText << " : " << selectedIndex + << " selected layout type is " << selectedLayoutType; + switch(selectedIndex) { + case 0: + break; + case 1: + if (selectedLayoutType==0) + slotLayoutCircularRandom(); + else if (selectedLayoutType==1) + slotLayoutRandom(); + break; + default: + if (selectedLayoutType==0) + slotLayoutCircularByProminenceIndex(selectedIndexText); + else if (selectedLayoutType==1) + slotLayoutLevelByProminenceIndex(selectedIndexText); + else if (selectedLayoutType==2){ + slotLayoutNodeSizesByProminenceIndex(selectedIndexText); + // re-init other options for node sizes... + nodeSizesByOutDegreeAct->setChecked(false); + toolBoxNodeSizesByOutDegreeBx->setChecked(false); + nodeSizesByInDegreeAct->setChecked(false); + toolBoxNodeSizesByInDegreeBx->setChecked(false); + } + break; + }; +} + + + +/** + * @brief MainWindow::toolBoxLayoutForceDirectedButtonPressed + * Called from MW, when user selects a model in the Layout by Force Directed + * selectbox of left panel. + */ +void MainWindow::toolBoxLayoutForceDirectedButtonPressed(){ + qDebug()<<"MW::toolBoxLayoutForceDirectedButtonPressed()"; + int selectedModel = toolBoxLayoutForceDirectedSelect->currentIndex(); + QString selectedModelText = toolBoxLayoutForceDirectedSelect -> currentText(); + qDebug() << " selected index is " << selectedModelText << " : " + << selectedModel; + + switch(selectedModel) { + case 0: + break; + case 1: + slotLayoutGuides(false); + slotLayoutSpringEmbedder(); + break; + case 2: + slotLayoutGuides(false); + slotLayoutFruchterman(); + break; + default: + toolBoxLayoutForceDirectedSelect->setCurrentIndex(0); + break; + }; +} + + + + + + +/** + * @brief MainWindow::resizeEvent + * Resizes the scene when the window is resized. + */ +void MainWindow::resizeEvent( QResizeEvent * ){ + + qDebug ("MW::resizeEvent(): window size %i, %i, graphicsWidget size %i, %i, scene %f,%f", + width(),height(), + graphicsWidget->width(),graphicsWidget->height(), + graphicsWidget->scene()->width(), graphicsWidget->scene()->height()); + + activeGraph.canvasSizeSet(graphicsWidget->width(),graphicsWidget->height()); + statusMessage( + QString( + tr("Window resized to (%1, %2)px. Canvas size: (%3, %4) px")) + .arg(width()).arg(height()) + .arg(graphicsWidget->width()).arg(graphicsWidget->height()) + ); + +} + + + + +/** + * @brief MainWindow::closeEvent + * @param ce + * Closes the application. Asks to write any unsaved network data. + */ void MainWindow::closeEvent( QCloseEvent* ce ) { if ( !networkModified ) { ce->accept(); @@ -2884,7 +4053,7 @@ void MainWindow::closeEvent( QCloseEvent* ce ) { 0, 1 ) ) { case 0: - slotFileSave(); + slotNetworkSave(); ce->accept(); break; case 1: @@ -2899,22 +4068,26 @@ void MainWindow::closeEvent( QCloseEvent* ce ) { - -void MainWindow::slotCreateNew() { - slotFileClose(); +/** + * @brief MainWindow::slotNetworkNew + * Creates a new network + */ +void MainWindow::slotNetworkNew() { + slotNetworkClose(); } + /** * @brief MainWindow::getLastPath * returns the last path used by user to open/save something */ QString MainWindow::getLastPath() { - if ( lastUsedDirPath == "socnetv-initial-none") { - lastUsedDirPath = QDir::homePath(); + if ( appSettings["lastUsedDirPath"] == "socnetv-initial-none") { + appSettings["lastUsedDirPath"] = appSettings["dataDir"]; } - qDebug() << lastUsedDirPath ; - return lastUsedDirPath ; + qDebug()<< "MW::getLastPath()" << appSettings["lastUsedDirPath"] ; + return appSettings["lastUsedDirPath"] ; } @@ -2923,16 +4096,45 @@ QString MainWindow::getLastPath() { * sets the last path used by user to open/save something * @param filePath */ -void MainWindow::setLastPath(QString filePath) { - lastUsedDirPath = filePath.left( filePath.lastIndexOf("/")); - qDebug() << lastUsedDirPath; -} +void MainWindow::setLastPath(QString fileName) { + qDebug()<< "MW::setLastPath() for " << fileName; + appSettings["lastUsedDirPath"] = QFileInfo(fileName).dir().absolutePath(); + // fileName.left( filePath.lastIndexOf("/")); + if ( !QFileInfo(fileName).completeSuffix().toLower().contains( "bmp" ) && + !QFileInfo(fileName).completeSuffix().toLower().contains( "jpg" ) && + !QFileInfo(fileName).completeSuffix().toLower().contains( "png" ) && + !QFileInfo(fileName).completeSuffix().toLower().contains( "pdf" ) + ) { + recentFiles.removeAll(fileName); + recentFiles.prepend(fileName); + while(recentFiles.size() > MaxRecentFiles ) + recentFiles.removeLast(); + } + slotNetworkFileRecentUpdateActions(); + saveSettings(); + qDebug() << appSettings["lastUsedDirPath"]; +} -void MainWindow::slotChooseFile() { - if (firstTime && fileFormat == -500 ) { +/** + * @brief MainWindow::slotNetworkFileChoose + * If m_fileName is empty, opens a file selection dialog + * Else + * Calls slotNetworkFilePreview() + * @param m_fileName + * @param m_fileFormat + * @param checkSelectFileType + */ +void MainWindow::slotNetworkFileChoose(QString m_fileName, + int m_fileFormat, + const bool &checkSelectFileType) { + qDebug() << "MW::slotNetworkFileChoose() start - " + << " m_fileName: " << m_fileName + << " m_fileFormat " << m_fileFormat + << " checkSelectFileType " << checkSelectFileType; + if (firstTime && m_fileFormat == -500 ) { QMessageBox::information( this, "SocNetV", tr("Attention: \n")+ tr("This menu option is more suitable for loading " @@ -2948,98 +4150,102 @@ void MainWindow::slotChooseFile() { "OK", 0 ); firstTime=false; } - if ( fileFormat == -1 ) - fileFormat = -1; bool a_file_was_already_loaded=fileLoaded; previous_fileName=fileName; - QString m_fileName, fileType_string; - int m_fileFormat=fileFormat; + QString fileType_string; - statusMessage( tr("Choose a network file...")); - switch (m_fileFormat){ - case 1: //GraphML - fileType_string = tr("GraphML (*.graphml *.xml);;All (*)"); - break; - case 2: //Pajek - fileType_string = tr("Pajek (*.net *.paj *.pajek);;All (*)"); - break; - case 3: //Adjacency - fileType_string = tr("Adjacency (*.csv *.sm *.adj);;All (*)"); - break; - case 4: //Dot - fileType_string = tr("GraphViz (*.dot);;All (*)"); - break; - case 5: //GML - fileType_string = tr("GML (*.gml);;All (*)"); - break; - case 6: //DL - fileType_string = tr("DL (*.dl);;All (*)"); - break; - case 7: // Weighted List - fileType_string = tr("Weighted List (*.wlst *.wlist);;All (*)"); - break; - case 8: // Simple List - fileType_string = tr("List (*.lst *.list);;All (*)"); - break; - case 9: // Two mode sm - fileType_string = tr("Two-Mode Sociomatrix (*.2sm *.aff);;All (*)"); - break; - default: //All - fileType_string = tr("GraphML (*.graphml *.xml);;Pajek (*.net *.pajek *.paj);;DL (*.dl *.dat);;Adjacency (*.csv *.adj *.sm);;GraphViz (*.dot);;List (*.lst *.list);;Weighted List (*.wlst *.wlist);;All (*)"); - break; + // prepare and open a file selection dialog + if (m_fileName.isNull()) { + statusMessage( tr("Choose a network file...")); - } + // prepare supported extensions strings + switch (m_fileFormat){ + case 1: //GraphML + fileType_string = tr("GraphML (*.graphml *.xml);;All (*)"); + break; + case 2: //Pajek + fileType_string = tr("Pajek (*.net *.paj *.pajek);;All (*)"); + break; + case 3: //Adjacency + fileType_string = tr("Adjacency (*.csv *.sm *.adj);;All (*)"); + break; + case 4: //Dot + fileType_string = tr("GraphViz (*.dot);;All (*)"); + break; + case 5: //GML + fileType_string = tr("GML (*.gml);;All (*)"); + break; + case 6: //DL + fileType_string = tr("DL (*.dl);;All (*)"); + break; + case 7: // Weighted List + fileType_string = tr("Weighted List (*.wlst *.wlist);;All (*)"); + break; + case 8: // Simple List + fileType_string = tr("List (*.lst *.csv *.list);;All (*)"); + break; + case 9: // Two mode sm + fileType_string = tr("Two-Mode Sociomatrix (*.2sm *.aff);;All (*)"); + break; + default: //All + fileType_string = tr("GraphML (*.graphml *.xml);;Pajek (*.net *.pajek *.paj);;DL (*.dl *.dat);;Adjacency (*.csv *.adj *.sm);;GraphViz (*.dot);;List (*.lst *.csv *.list);;Weighted List (*.wlst *.wlist);;All (*)"); + break; - m_fileName = QFileDialog::getOpenFileName( - this, - tr("Select one file to open"), - getLastPath(), fileType_string ); + } + m_fileName = QFileDialog::getOpenFileName( + this, + tr("Select a network file to open"), + getLastPath(), fileType_string); + } + qDebug() << "MW::slotNetworkFileChoose() - " + << " m_fileName: " << m_fileName; if (checkSelectFileType) { //check if user has changed the filetype filter and loaded other filetype if (m_fileName.endsWith(".graphml",Qt::CaseInsensitive ) || m_fileName.endsWith(".xml",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=1; + m_fileFormat=1; } else if (m_fileName.endsWith(".net",Qt::CaseInsensitive ) || m_fileName.endsWith(".paj",Qt::CaseInsensitive ) || m_fileName.endsWith(".pajek",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=2; + m_fileFormat=2; } else if (m_fileName.endsWith(".sm",Qt::CaseInsensitive ) || - m_fileName.endsWith(".dat",Qt::CaseInsensitive ) || + m_fileName.endsWith(".dat",Qt::CaseInsensitive ) || + m_fileName.endsWith(".csv",Qt::CaseInsensitive ) || m_fileName.endsWith(".adj",Qt::CaseInsensitive ) || m_fileName.endsWith(".txt",Qt::CaseInsensitive )) { - fileFormat=m_fileFormat=3; + m_fileFormat=3; } else if (m_fileName.endsWith(".dot",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=4; + m_fileFormat=4; } else if (m_fileName.endsWith(".gml",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=5; + m_fileFormat=5; } else if (m_fileName.endsWith(".dl",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=6; + m_fileFormat=6; } else if (m_fileName.endsWith(".list",Qt::CaseInsensitive ) || m_fileName.endsWith(".lst",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=7; + m_fileFormat=7; } else if (m_fileName.endsWith(".wlist",Qt::CaseInsensitive ) || m_fileName.endsWith(".wlst",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=8; + m_fileFormat=8; } else if (m_fileName.endsWith(".2sm",Qt::CaseInsensitive ) || m_fileName.endsWith(".aff",Qt::CaseInsensitive ) ) { - fileFormat=m_fileFormat=9; + m_fileFormat=9; } else - fileFormat=m_fileFormat=-1; + m_fileFormat=-1; } - if (!m_fileName.isEmpty()) { + if (!m_fileName.isEmpty() && !m_fileName.isNull()) { if (m_fileFormat == -1) { - QMessageBox::critical(this, "Unrecognized file extension", tr("Error! \n" + QMessageBox::critical(this, "Unrecognized file", tr("Error! \n" "SocNetV supports the following network file" "formats. The filename you selected does not " "end with any of the following extensions:\n" @@ -3054,12 +4260,19 @@ void MainWindow::slotChooseFile() { "If you are sure the file is of a supported " "format, perhaps you should just change its extension..."), QMessageBox::Ok, 0); + statusMessage( tr("Error: Unrecognized file. ")); + //if a file was previously opened, get back to it. + if (a_file_was_already_loaded) { + fileLoaded=true; + fileName=previous_fileName; + } + return; } - qDebug()<<"MW: file selected: " << m_fileName; - fileNameNoPath=m_fileName.split ("/"); - setLastPath(m_fileName); // store this path + qDebug()<<"MW::slotNetworkFileChoose() - selected file: " << m_fileName + << " fileFormat " << m_fileFormat; + + slotNetworkFilePreview(m_fileName, m_fileFormat ); - previewNetworkFile(m_fileName, m_fileFormat ); } else { @@ -3077,9 +4290,10 @@ void MainWindow::slotChooseFile() { /** - Saves the network in the same file -*/ -void MainWindow::slotFileSave() { + * @brief MainWindow::slotNetworkSave + * Saves the network in the same file + */ +void MainWindow::slotNetworkSave() { statusMessage( tr("Saving file...")); if (!fileLoaded && !networkModified ) { @@ -3087,7 +4301,7 @@ void MainWindow::slotFileSave() { return; } if ( fileName.isEmpty() ) { - slotFileSaveAs(); + slotNetworkSaveAs(); return; } @@ -3140,10 +4354,12 @@ void MainWindow::slotFileSave() { + /** - Saves the network in a new file -*/ -void MainWindow::slotFileSaveAs() { + * @brief MainWindow::slotNetworkSaveAs + * Saves the network in a new file + */ +void MainWindow::slotNetworkSaveAs() { statusMessage( tr("Saving network under new filename...")); QString fn = QFileDialog::getSaveFileName( @@ -3161,7 +4377,7 @@ void MainWindow::slotFileSaveAs() { adjacencyFileLoaded=false; pajekFileLoaded=false; graphMLFileLoaded=false; - slotFileSave(); + slotNetworkSave(); } else { statusMessage( tr("Saving aborted")); @@ -3172,20 +4388,22 @@ void MainWindow::slotFileSaveAs() { -/* - * Called from Graph when we try to save file +/** + * @brief MainWindow::networkSaved + * @param saved_ok + * Called from Graph when we try to save file */ void MainWindow::networkSaved(int saved_ok) { if (saved_ok <= 0) { - graphChanged(); + slotNetworkChanged(); statusMessage( tr("Error! Could not save this file... ")+fileNameNoPath.last()+tr(".") ); } else { - fileSave->setIcon(QIcon(":/images/saved.png")); - fileSave->setEnabled(false); + networkSave->setIcon(QIcon(":/images/saved.png")); + networkSave->setEnabled(false); fileLoaded=true; networkModified=false; setWindowTitle( fileNameNoPath.last() ); statusMessage( tr("Network saved under filename: ")+fileNameNoPath.last()+tr(".") ); @@ -3214,20 +4432,22 @@ void MainWindow::networkSaved(int saved_ok) } } + + /** - Closes the network. Saves it if necessary. - Used by createNew. -*/ -void MainWindow::slotFileClose() { - statusMessage( tr("Closing file...")); - qDebug()<<"slotFileClose()"; + * @brief MainWindow::slotNetworkClose + * Closes the network. Saves it if necessary. Used by createNew. + */ +void MainWindow::slotNetworkClose() { + qDebug()<<"slotNetworkClose()"; + statusMessage( tr("Closing network file...")); if (networkModified) { switch ( QMessageBox::information (this, "Closing Network...", tr("Network has not been saved. \nDo you want to save before closing it?"), "Yes", "No",0,1)) { - case 0: slotFileSave(); break; + case 0: slotNetworkSave(); break; case 1: break; } } @@ -3239,9 +4459,10 @@ void MainWindow::slotFileClose() { /** - Prints whatever is viewable on the Graphics widget -*/ -void MainWindow::slotPrintView() { + * @brief MainWindow::slotNetworkPrint + * Sends the active network to the printer + */ +void MainWindow::slotNetworkPrint() { statusMessage( tr("Printing...")); QPrintDialog dialog(printer, this); if ( dialog.exec() ) { @@ -3254,84 +4475,92 @@ void MainWindow::slotPrintView() { -/** - Imports a network from a formatted file -*/ -void MainWindow::slotImportGraphML(){ -// fileFormat=-1; -// checkSelectFileType = true; - this->slotChooseFile(); + +/** + * @brief MainWindow::slotNetworkImportGraphML + * Imports a network from a GraphML formatted file + */ +void MainWindow::slotNetworkImportGraphML(){ + int m_fileFormat=1; + bool m_checkSelectFileType = false; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); } -/** - Imports a network from a formatted file -*/ -void MainWindow::slotImportPajek(){ - fileFormat=2; - checkSelectFileType = false; - this->slotChooseFile(); + +/** + * @brief MainWindow::slotNetworkImportPajek + * Imports a network from a Pajek-like formatted file + */ +void MainWindow::slotNetworkImportPajek(){ + int m_fileFormat=2; + bool m_checkSelectFileType = false; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); } -/** - Imports a network from a Adjacency matrix formatted file -*/ -void MainWindow::slotImportSM(){ - fileFormat=3; - checkSelectFileType = false; - this->slotChooseFile(); + +/** + * @brief MainWindow::slotNetworkImportSM + * Imports a network from a Adjacency matrix formatted file + */ +void MainWindow::slotNetworkImportSM(){ + int m_fileFormat=3; + bool m_checkSelectFileType = false; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); } + /** - Imports a network from a two mode sociomatrix formatted file -*/ -void MainWindow::slotImportTwoModeSM(){ - fileFormat=9; - checkSelectFileType = false; - this->slotChooseFile(); + * @brief MainWindow::slotNetworkImportDot + * Imports a network from a Dot formatted file + */ +void MainWindow::slotNetworkImportDot(){ + int m_fileFormat=4; + bool m_checkSelectFileType = false; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); } -/** - Imports a network from a Dot formatted file -*/ -void MainWindow::slotImportDot(){ - fileFormat=4; - checkSelectFileType = false; - this->slotChooseFile(); + +/** + * @brief MainWindow::slotNetworkImportGML + * Imports a network from a GML formatted file + */ +void MainWindow::slotNetworkImportGML(){ + int m_fileFormat=5; + bool m_checkSelectFileType = false; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); + } -/** - Imports a network from a GML formatted file -*/ -void MainWindow::slotImportGML(){ - fileFormat=5; - checkSelectFileType = false; - this->slotChooseFile(); + +/** + * @brief MainWindow::slotNetworkImportDL + * Imports a network from a UCINET formatted file + */ +void MainWindow::slotNetworkImportDL(){ + int m_fileFormat=6; + bool m_checkSelectFileType = false; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); } -/** - Imports a network from a UCINET formatted file -*/ -void MainWindow::slotImportDL(){ - fileFormat=6; - checkSelectFileType = false; - this->slotChooseFile(); -} +/** + * @brief MainWindow::slotNetworkImportEdgeList + * Imports a network from a List formatted file + */ +void MainWindow::slotNetworkImportEdgeList(){ -/** - Imports a network from a List formatted file -*/ -void MainWindow::slotImportEdgeList(){ + int m_fileFormat = 0; + bool m_checkSelectFileType = false; switch( QMessageBox::question( this, "Type of list format", tr("I can parse two kinds of lists: \n\n")+ tr("A. Weighted lists, with each line having exactly 3 columns (source, target, weight), i.e.\n 1 2 5 \n \n")+ @@ -3341,20 +4570,37 @@ void MainWindow::slotImportEdgeList(){ ) { case 0: - qDebug() << "*** MW: slotImportEdgeList - Weighted list selected! " ; - fileFormat = 7; + qDebug() << "*** MW::slotNetworkImportEdgeList - Weighted list selected! " ; + m_fileFormat = 7; + slotNetworkFileChoose( QString::null, m_fileFormat, m_checkSelectFileType); break; case 1: - qDebug() << "*** MW: slotImportEdgeList - Simple list selected! " ; - fileFormat = 8; + qDebug() << "*** MW: slotNetworkImportEdgeList - Simple list selected! " ; + m_fileFormat = 8; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); break; } - checkSelectFileType = false; - this->slotChooseFile(); } -void MainWindow::findCodecs() + +/** + * @brief MainWindow::slotNetworkImportTwoModeSM + * Imports a network from a two mode sociomatrix formatted file + */ +void MainWindow::slotNetworkImportTwoModeSM(){ + int m_fileFormat=9; + bool m_checkSelectFileType = false; + slotNetworkFileChoose( QString::null ,m_fileFormat, m_checkSelectFileType); +} + + + +/** + * @brief MainWindow::slotNetworkAvailableTextCodecs + * Setup a list of all text codecs supported by current OS + */ +void MainWindow::slotNetworkAvailableTextCodecs() { QMap codecMap; QRegExp iso8859RegExp("ISO[- ]8859-([0-9]+).*"); @@ -3386,19 +4632,29 @@ void MainWindow::findCodecs() -bool MainWindow::previewNetworkFile(QString m_fileName, int m_fileFormat ){ - qDebug() << "MW::previewNetworkFile() : "<< m_fileName; +/** + * @brief MainWindow::slotNetworkFilePreview + * @param m_fileName + * @param m_fileFormat + * @return + * Called from slotNetworkFileChoose() + * Opens a window to preview the selected file where the user + * can select an appropriate text codec + */ +bool MainWindow::slotNetworkFilePreview(const QString &m_fileName, + const int &m_fileFormat ){ + qDebug() << "MW::slotNetworkFilePreview() : "<< m_fileName; if (!m_fileName.isEmpty()) { QFile file(m_fileName); if (!file.open(QFile::ReadOnly)) { - QMessageBox::warning(this, tr("previewNetworkFile"), + QMessageBox::warning(this, tr("Network File Previewer"), tr("Cannot read file %1:\n%2") .arg(m_fileName) .arg(file.errorString())); return false; } - qDebug() << "MW::loadNetworkFile() reading the file now... " ; + qDebug() << "MW::slotNetworkFilePreview() reading the file now... " ; QByteArray data = file.readAll(); previewForm->setEncodedData(data,m_fileName, m_fileFormat); @@ -3407,19 +4663,40 @@ bool MainWindow::previewNetworkFile(QString m_fileName, int m_fileFormat ){ return true; } -void MainWindow::userCodec(const QString m_fileName, - const QString m_codecName, - const int m_fileFormat) { - loadNetworkFile(m_fileName, m_codecName, m_fileFormat ); + + + +/** + * @brief MainWindow::slotNetworkFileLoadRecent + * Called on click on any file entry in "Recent Files" menu + * Calls slotNetworkFileChoose() which checks file type and calls slotNetworkFilePreview + */ +void MainWindow::slotNetworkFileLoadRecent() { + QAction *action = qobject_cast(sender()); + if (action) { + slotNetworkFileChoose(action->data().toString() ); + } } -bool MainWindow::loadNetworkFile(const QString m_fileName, + +/** + * @brief MainWindow::slotNetworkFileLoad + * @param m_fileName + * @param m_codecName + * @param m_fileFormat + * @return + * Main network file loader method + * Called from previewForm and slotNetworkDataSetRecreate + * Calls initNet to init to default values. + * Then calls activeGraph::loadGraph to actually load the network... + */ +bool MainWindow::slotNetworkFileLoad(const QString m_fileName, const QString m_codecName, const int m_fileFormat ) { - qDebug() << "MW::loadNetworkFile() : "<< m_fileName + qDebug() << "MW::slotNetworkFileLoad() : "<< m_fileName << " m_codecName " << m_codecName << " m_fileFormat " << m_fileFormat; initNet(); @@ -3445,16 +4722,16 @@ bool MainWindow::loadNetworkFile(const QString m_fileName, } QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - qDebug() << "MW::loadNetworkFile() : calling activeGraph.loadGraph() "; + qDebug() << "MW::slotNetworkFileLoad() : calling activeGraph.loadGraph() "; bool loadGraphStatus = activeGraph.loadGraph ( m_fileName, m_codecName, - displayNodeLabelsAct->isChecked(), + (appSettings["initNodeLabelsVisibility"] == "true" ) ? true: false, graphicsWidget->width(), graphicsWidget->height(), m_fileFormat, two_sm_mode ); - qDebug() << "MW::loadNetworkFile() : loadGraphStatus " << loadGraphStatus; + qDebug() << "MW::slotNetworkFileLoad() : loadGraphStatus " << loadGraphStatus; if ( loadGraphStatus ) { fileName=m_fileName; @@ -3462,8 +4739,10 @@ bool MainWindow::loadNetworkFile(const QString m_fileName, fileNameNoPath = fileName.split("/"); Q_ASSERT_X( !fileNameNoPath.isEmpty(), "not empty filename ", "empty filename " ); setWindowTitle("SocNetV "+ VERSION +" - "+fileNameNoPath.last()); + setLastPath(m_fileName); // store this path and file QString message=tr("Loaded network: ")+fileNameNoPath.last(); statusMessage( message ); + slotNetworkChanged(); } else { statusMessage( tr("Error loading requested file. Aborted.")); @@ -3475,7 +4754,7 @@ bool MainWindow::loadNetworkFile(const QString m_fileName, "OK", 0 ); } QApplication::restoreOverrideCursor(); - qDebug() << "MW::loadNetworkFile() : returning " << loadGraphStatus; + qDebug() << "MW::slotNetworkFileLoad() : returning " << loadGraphStatus; return loadGraphStatus; } @@ -3600,39 +4879,40 @@ void MainWindow::fileType ( " which is the file-format using Import Menu.","OK",0); break; } - graphChanged(); - fileSave->setIcon(QIcon(":/images/saved.png")); - fileSave->setEnabled(false); + slotNetworkChanged(); + networkSave->setIcon(QIcon(":/images/saved.png")); + networkSave->setEnabled(false); } + /** - * @brief MainWindow::prevRelation - * Decreases the index of changeRelationCombo - * which signals to Graph::changeRelation() + * @brief MainWindow::slotEditRelationPrev + * Decreases the index of editRelationChangeCombo + * which signals to Graph::relationSet() */ -void MainWindow::prevRelation(){ - qDebug() << "MW::prevRelation()"; - int index=changeRelationCombo->currentIndex(); +void MainWindow::slotEditRelationPrev(){ + qDebug() << "MW::slotEditRelationPrev()"; + int index=editRelationChangeCombo->currentIndex(); if (index>0){ --index; filterIsolateNodesAct->setChecked(false); - changeRelationCombo->setCurrentIndex(index); + editRelationChangeCombo->setCurrentIndex(index); } } /** - * @brief MainWindow::nextRelation - * Increases the index of changeRelationCombo - * which signals to Graph::changeRelation() + * @brief MainWindow::slotEditRelationNext + * Increases the index of editRelationChangeCombo + * which signals to Graph::relationSet() */ -void MainWindow::nextRelation(){ - qDebug() << "MW::nextRelation()"; - int index=changeRelationCombo->currentIndex(); - int relationsCounter=changeRelationCombo->count(); +void MainWindow::slotEditRelationNext(){ + qDebug() << "MW::slotEditRelationNext()"; + int index=editRelationChangeCombo->currentIndex(); + int relationsCounter=editRelationChangeCombo->count(); if (index< (relationsCounter -1 )){ ++index; filterIsolateNodesAct->setChecked(false); - changeRelationCombo->setCurrentIndex(index); + editRelationChangeCombo->setCurrentIndex(index); } } @@ -3640,59 +4920,59 @@ void MainWindow::nextRelation(){ /** - * @brief MainWindow::addRelation - * called from activeGraph::addRelationFromGraph(QString) when the parser or a + * @brief MainWindow::slotEditRelationAdd + * called from activeGraph::relationAddFromGraph(QString) when the parser or a * Graph method demands a new relation to be added in the Combobox. * @param relationName (NULL) */ -void MainWindow::addRelation(QString relationName){ - qDebug() << "MW::addRelation(string)" << relationName; +void MainWindow::slotEditRelationAdd(QString relationName){ + qDebug() << "MW::slotEditRelationAdd(string)" << relationName; if ( !relationName.isNull() ){ - changeRelationCombo->addItem(relationName); + editRelationChangeCombo->addItem(relationName); } } /** - * @brief MainWindow::addRelation + * @brief MainWindow::slotEditRelationAdd * Called from MW when user clicks New Relation btn * or when the user creates the first edge visually. */ -void MainWindow::addRelation(){ - qDebug() << "MW::addRelation()"; +void MainWindow::slotEditRelationAdd(){ + qDebug() << "MW::slotEditRelationAdd()"; bool ok; QString newRelationName; - int relationsCounter=changeRelationCombo->count(); + int relationsCounter=editRelationChangeCombo->count(); if (relationsCounter==0) { - newRelationName = QInputDialog::getText(this, tr("Add new relation"), - tr("Since you have just created the first edge " - "of this social network, please enter a name \n" - "for this new relation between the actors.\n " - "A relation is a collection of ties of a " - "specific kind between the network actors.\n" - "For instance, enter \"friendship\" if the " - "edges of this relation refer to the set of \n" - "friendships between pairs of actors."), + newRelationName = QInputDialog::getText( + this, + tr("Add new relation"), + tr("Enter a name for this new relation between the actors.\n" + "A relation is a collection of ties of a " + "specific kind between the network actors.\n" + "For instance, enter \"friendship\" if the " + "edges of this relation refer to the set of \n" + "friendships between pairs of actors."), QLineEdit::Normal, QString::null, &ok ); } else { newRelationName = QInputDialog::getText( this, tr("Add new relation"), - tr("Please enter a name for the new relation:"), + tr("Enter a name for the new relation (or press Cancel):"), QLineEdit::Normal,QString::null, &ok ); } if (ok && !newRelationName.isEmpty()){ - changeRelationCombo->addItem(newRelationName); + editRelationChangeCombo->addItem(newRelationName); emit addRelationToGraph(newRelationName); if (relationsCounter != 0){ //dont do it if its the first relation added - qDebug() << "MW::addRelation() - updating combo index"; - changeRelationCombo->setCurrentIndex(relationsCounter); + qDebug() << "MW::slotEditRelationAdd() - updating combo index"; + editRelationChangeCombo->setCurrentIndex(relationsCounter); } } else if ( newRelationName.isEmpty() && ok ){ QMessageBox::critical(this, tr("Error"), tr("You did not type a name for this new relation"), QMessageBox::Ok, 0); - addRelation(); + slotEditRelationAdd(); } else { statusMessage( QString(tr("New relation cancelled.")) ); @@ -3704,43 +4984,21 @@ void MainWindow::addRelation(){ -/** - Calls Graph::createVertex method to add a new RANDOM node into the activeGraph. - Called when "Create Node" button is clicked on the Main Window. -*/ -void MainWindow::addNode() { - qDebug() << "MW::addNode() "; - // minus a screen edge offset... - activeGraph.createVertex ( - -1, graphicsWidget->width()-10, graphicsWidget->height()-10); - statusMessage( tr("New node (numbered %1) added.") - .arg(activeGraph.lastVertexNumber()) ); -} - - -/** - Calls Graph::createVertex method to add a new node into the activeGraph. - Called on double clicking -*/ -void MainWindow::addNodeWithMouse(int num, QPointF p) { - qDebug("MW: addNodeWithMouse(). Calling activeGraph::createVertex() for a vertex named %i", num); - activeGraph.createVertex(num, p); - statusMessage( tr("New node (numbered %1) added.").arg(activeGraph.lastVertexNumber()) ); -} - /** - Exports the network to a PNG image - Mediocre Quality but smaller file -*/ - -bool MainWindow::slotExportPNG(){ - qDebug("slotExportPNG"); + * @brief MainWindow::slotExportPNG + * @return + * Exports the network to a PNG image - Mediocre Quality but smaller file + */ +bool MainWindow::slotNetworkExportPNG(){ + qDebug()<< "MW::slotNetworkExportPNG"; if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("The canvas is empty!\nLoad a network file or create a new network first."), "OK",0); + QMessageBox::critical(this, "Error", + tr("The canvas is empty!\n" + "Load a network file or create a new network first."), "OK",0); statusMessage( tr("Cannot export PNG.") ); return false; } @@ -3760,7 +5018,13 @@ bool MainWindow::slotExportPNG(){ QPainter p; p.begin(&picture); p.setFont(QFont ("Helvetica", 10, QFont::Normal, false)); - p.drawText(5,10,"SocNetV: "+tempFileNameNoPath.last()); + if (appSettings["printLogo"]=="true") { + QImage logo(":/images/socnetv-logo.png"); + p.drawImage(5,5, logo); + p.drawText(7,47,tempFileNameNoPath.last()); + } + else + p.drawText(5,15,tempFileNameNoPath.last()); p.end(); qDebug("slotExportPNG: checking filename"); if (fn.contains("png", Qt::CaseInsensitive) ) { @@ -3783,14 +5047,21 @@ bool MainWindow::slotExportPNG(){ + /** - Exports the network to a BMP image - Better Quality but larger file -*/ -bool MainWindow::slotExportBMP(){ - qDebug( "slotExportBMP()"); + * @brief MainWindow::slotNetworkExportBMP + * @return + * Exports the network to a BMP image - Better Quality but larger file + */ +bool MainWindow::slotNetworkExportBMP(){ + qDebug( "slotNetworkExportBMP()"); if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to export! \nLoad a network file or create a new network first."), "OK",0); + QMessageBox::critical(this, + "Error", + tr( + "Nothing to export! \n" + "Load a network file or create a new network first."), + "OK",0); statusMessage( tr("Cannot export BMP.") ); return false; } @@ -3805,15 +5076,21 @@ bool MainWindow::slotExportBMP(){ tempFileNameNoPath=fn.split ("/"); QPixmap picture; - qDebug("slotExportBMP: grabbing canvas"); + qDebug("slotNetworkExportBMP: grabbing canvas"); picture=QPixmap::grabWidget(graphicsWidget, graphicsWidget->viewport()->rect()); QPainter p; - qDebug("slotExportBMP: adding logo"); + qDebug("slotNetworkExportBMP: adding logo"); p.begin(&picture); p.setFont(QFont ("Helvetica", 10, QFont::Normal, false)); - p.drawText(5,10,"SocNetV: "+tempFileNameNoPath.last()); + if (appSettings["printLogo"]=="true") { + QImage logo(":/images/socnetv-logo.png"); + p.drawImage(5,5, logo); + p.drawText(7,47,tempFileNameNoPath.last()); + } + else + p.drawText(5,15,tempFileNameNoPath.last()); p.end(); - qDebug("slotExportBMP: checking file"); + qDebug("slotNetworkExportBMP: checking file"); if (fn.contains(format, Qt::CaseInsensitive) ) { picture.toImage().save(fn, format.toLatin1()); QMessageBox::information(this, tr("Export to BMP..."), @@ -3837,13 +5114,17 @@ bool MainWindow::slotExportBMP(){ /** - Exports the network to a PDF Document - Best Quality -*/ -bool MainWindow::slotExportPDF(){ - qDebug( "slotExportPDF()"); + * @brief MainWindow::slotExportPDF + * @return + * Exports the network to a PDF Document - Best Quality + */ +bool MainWindow::slotNetworkExportPDF(){ + qDebug()<< "MW::slotNetworkExportPDF()"; if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("The canvas is empty!\nLoad a network file or create a new network first."), "OK",0); + QMessageBox::critical(this, + "Error", + tr("The canvas is empty!\n" + "Load a network file or create a new network first."), "OK",0); statusMessage( tr("Cannot export PDF.") ); return false; } @@ -3859,16 +5140,22 @@ bool MainWindow::slotExportPDF(){ if (QFileInfo(m_fileName).suffix().isEmpty()) m_fileName.append(".pdf"); - QPrinter printer(QPrinter::HighResolution); + // dont set to HighResolution - it breaks pdf export + QPrinter printer(QPrinter::ScreenResolution); printer.setOutputFormat(QPrinter::PdfFormat); printer.setOutputFileName(m_fileName); - QPainter painter(&printer); - graphicsWidget->render(&painter); + QPainter p; + p.begin(&printer); + graphicsWidget->render(&p); + p.end(); + } qDebug()<< "Exporting PDF to "<< m_fileName; tempFileNameNoPath=m_fileName.split ("/"); setLastPath(m_fileName); - QMessageBox::information(this, tr("Export to PDF..."),tr("File saved as: ")+tempFileNameNoPath.last() , "OK",0); + QMessageBox::information(this, tr("Export to PDF..."), + tr("File saved as: ")+tempFileNameNoPath.last() , + "OK",0); statusMessage( tr("Exporting completed") ); return true; } @@ -3877,12 +5164,13 @@ bool MainWindow::slotExportPDF(){ /** - Exports the network to a Pajek-formatted file - Calls the relevant Graph method. -*/ -void MainWindow::slotExportPajek() + * @brief MainWindow::slotExportPajek + * Exports the network to a Pajek-formatted file + * Calls the relevant Graph method. + */ +void MainWindow::slotNetworkExportPajek() { - qDebug ("MW: slotExportPajek"); + qDebug () << "MW::slotNetworkExportPajek"; if (!fileLoaded && !networkModified ) { QMessageBox::critical(this, "Error",tr("Nothing to export! \nLoad a network file or create a new network first."), "OK",0); @@ -3920,11 +5208,13 @@ void MainWindow::slotExportPajek() -/** Exports the network to a adjacency matrix-formatted file - Calls the relevant Graph method. -*/ -void MainWindow::slotExportSM(){ - qDebug("MW: slotExportSM()"); +/** + * @brief MainWindow::slotNetworkExportSM + * Exports the network to a adjacency matrix-formatted file + * Calls the relevant Graph method. + */ +void MainWindow::slotNetworkExportSM(){ + qDebug("MW: slotNetworkExportSM()"); if (!fileLoaded && !networkModified ) { QMessageBox::critical(this, "Error",tr("Nothing to export!\nLoad a network file or create a new network first."), "OK",0); statusMessage( tr("Cannot export to Adjacency Matrix.") ); @@ -3963,12 +5253,12 @@ void MainWindow::slotExportSM(){ - /** - Exports the network to a DL-formatted file - TODO slotExportDL -*/ -bool MainWindow::slotExportDL(){ + * @brief MainWindow::slotNetworkExportDL + * @return Exports the network to a DL-formatted file + * - TODO slotNetworkExportDL + */ +bool MainWindow::slotNetworkExportDL(){ if (!fileLoaded && !networkModified ) { QMessageBox::critical(this, "Error",tr("Nothing to export!\nLoad a network file or create a new network first."), "OK",0); statusMessage( tr("Cannot export to DL.") ); @@ -3996,9 +5286,9 @@ bool MainWindow::slotExportDL(){ /** Exports the network to a GW-formatted file - TODO slotExportGW + TODO slotNetworkExportGW */ -bool MainWindow::slotExportGW(){ +bool MainWindow::slotNetworkExportGW(){ if (!fileLoaded && !networkModified ) { QMessageBox::critical(this, "Error",tr("Nothing to export!\nLoad a network file or create a new network first."), "OK",0); statusMessage( tr("Cannot export to GW.") ); @@ -4027,9 +5317,9 @@ bool MainWindow::slotExportGW(){ /** Exports the network to a list-formatted file - TODO slotExportList + TODO slotNetworkExportList */ -bool MainWindow::slotExportList(){ +bool MainWindow::slotNetworkExportList(){ if (fileName.isEmpty()) { statusMessage( tr("Saving network under new filename...")); QString fn = QFileDialog::getSaveFileName( @@ -4053,12 +5343,13 @@ bool MainWindow::slotExportList(){ /** - Displays the file of the loaded network. - Network _must_ be unchanged since last save/load. - Otherwise it will ask the user to first save the network, then view its file. -*/ -void MainWindow::slotViewNetworkFile(){ - qDebug() << "slotViewNetworkFile() : " << fileName.toLatin1(); + * @brief MainWindow::slotNetworkFileView + * Displays the file of the loaded network. + Network _must_ be unchanged since last save/load. + Otherwise it will ask the user to first save the network, then view its file. + */ +void MainWindow::slotNetworkFileView(){ + qDebug() << "slotNetworkFileView() : " << fileName.toLatin1(); if ( fileLoaded && !networkModified ) { //file network unmodified QFile f( fileName ); if ( !f.open( QIODevice::ReadOnly ) ) { @@ -4073,15 +5364,15 @@ void MainWindow::slotViewNetworkFile(){ else if (fileName.isEmpty() && networkModified) { //New network + something QMessageBox::information (this, "Viewing network file", tr("This network has not been saved yet. \nI will open a dialog for you to save it now. \nPlease choose a filename..."), "OK",0); - slotFileSaveAs(); + slotNetworkSaveAs(); } else if (fileLoaded && networkModified ) { //file network + modified QMessageBox::information (this, "Viewing network file", //FIXME maybe better to save automagically rather than asking? tr("The network has been modified. \nI will save it to the original file for you now."), "OK",0); networkModified = false; - slotFileSave(); - slotViewNetworkFile(); + slotNetworkSave(); + slotNetworkFileView(); } else { QMessageBox::critical(this, "Error", @@ -4094,10 +5385,11 @@ void MainWindow::slotViewNetworkFile(){ /** - Opens the embedded text editor -*/ -void MainWindow::slotOpenTextEditor(){ - qDebug() << "slotOpenTextEditor() : "; + * @brief MainWindow::slotNetworkTextEditor + * Opens the embedded text editor + */ +void MainWindow::slotNetworkTextEditor(){ + qDebug() << "slotNetworkTextEditor() : "; TextEditor *ed = new TextEditor("", this); ed->setWindowTitle(tr("New Network File")); @@ -4110,12 +5402,14 @@ void MainWindow::slotOpenTextEditor(){ /** - Displays the adjacency matrix of the network. - It uses a different method for writing the matrix to a file. - While slotExportSM uses << operator of Matrix class (via adjacencyMatrix of Graph class), - this is using directly the writeAdjacencyMatrix method of Graph class -*/ -void MainWindow::slotViewAdjacencyMatrix(){ + * @brief MainWindow::slotNetworkViewSociomatrix + * Displays the adjacency matrix of the network. + * It uses a different method for writing the matrix to a file. + * While slotNetworkExportSM uses << operator of Matrix class + * (via adjacencyMatrix of Graph class), this is using directly the + * writeAdjacencyMatrix method of Graph class + */ +void MainWindow::slotNetworkViewSociomatrix(){ if ( !fileLoaded && !networkModified) { QMessageBox::critical (this, "Error", tr("Empty network! \nLoad a network file or create something by double-clicking on the canvas!"), "OK",0); @@ -4126,41 +5420,44 @@ void MainWindow::slotViewAdjacencyMatrix(){ int aNodes=activeNodes(); statusBar() -> showMessage ( QString (tr ("creating adjacency adjacency matrix of %1 nodes")).arg(aNodes) ); qDebug ("MW: calling Graph::writeAdjacencyMatrix with %i nodes", aNodes); - QString fn = dataDir + "socnetv-report-adjacency-matrix.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-adjacency-matrix.dat"; activeGraph.writeAdjacencyMatrix(fn, networkName.toLocal8Bit()) ; //Open a text editor window for the new file created by graph class TextEditor *ed = new TextEditor(fn); - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - statusMessage(tr("Adjacency Matrix saved at ") + tempFileNameNoPath.last()); + statusMessage(tr("Adjacency Matrix saved as ") + fn); } -/* - * Calls the m_datasetSelectionDialog to display the datasetselection dialog +/** + * @brief MainWindow::slotNetworkDataSetSelect + * Calls the m_datasetSelectionDialog to display the dataset selection dialog */ -void MainWindow::slotShowDataSetSelectDialog(){ - qDebug()<< "slotShowDataSetSelectDialog()"; +void MainWindow::slotNetworkDataSetSelect(){ + qDebug()<< "MW::slotNetworkDataSetSelect()"; m_datasetSelectDialog.exec(); } -/* - * Recreates some of the most famous and widely used data sets - * in network analysis studies + +/** + * @brief MainWindow::slotNetworkDataSetRecreate + * @param m_fileName + * Recreates some of the most famous and widely used data sets in + * network analysis studies */ -void MainWindow::slotRecreateDataSet (QString m_fileName) { +void MainWindow::slotNetworkDataSetRecreate (const QString m_fileName) { int m_fileFormat=0; - qDebug()<< "slotRecreateDataSet() fileName: " << m_fileName; + qDebug()<< "MW::slotNetworkDataSetRecreate() fileName: " << m_fileName; //initNet(); - qDebug()<< "slotRecreateDataSet() datadir+fileName: " << dataDir+m_fileName; - activeGraph.writeDataSetToFile(dataDir, m_fileName); + qDebug()<< "MW::slotNetworkDataSetRecreate() datadir+fileName: " + << appSettings["dataDir"]+m_fileName; + activeGraph.writeDataSetToFile(appSettings["dataDir"], m_fileName); if (m_fileName.endsWith(".graphml")) { m_fileFormat=1; @@ -4190,9 +5487,8 @@ void MainWindow::slotRecreateDataSet (QString m_fileName) { else if (m_fileName.endsWith(".2sm")) { m_fileFormat=9; } - checkSelectFileType = false; - if ( loadNetworkFile(dataDir+m_fileName, "UTF-8", m_fileFormat) ) { - qDebug() << "slotRecreateDataSet() loaded file " << m_fileName; + if ( slotNetworkFileLoad(appSettings["dataDir"]+m_fileName, "UTF-8", m_fileFormat) ) { + qDebug() << "slotNetworkDataSetRecreate() loaded file " << m_fileName; fileName=m_fileName; previous_fileName=fileName; setWindowTitle("SocNetV "+ VERSION +" - "+fileName); @@ -4204,89 +5500,84 @@ void MainWindow::slotRecreateDataSet (QString m_fileName) { } } + /** - Calls activeGraph.createRandomNetErdos () to create a symmetric network - Edge existance is controlled by a user specified possibility. -*/ -void MainWindow::slotCreateRandomErdosRenyi(){ + * @brief MainWindow::slotRandomErdosRenyiDialog + * Shows the Erdos-Renyi network creation dialog + */ +void MainWindow::slotRandomErdosRenyiDialog(){ statusMessage( "Creating a random symmetric network... "); - m_randErdosRenyiDialog = new RandErdosRenyiDialog(this); + m_randErdosRenyiDialog = new RandErdosRenyiDialog( + this, appSettings["randomErdosEdgeProbability"].toFloat(0)); connect( m_randErdosRenyiDialog, &RandErdosRenyiDialog::userChoices, - this, &MainWindow::createRandomNetErdos ); - + this, &MainWindow::slotRandomErdosRenyi ); m_randErdosRenyiDialog->exec(); - } - - -void MainWindow::createRandomNetErdos( const int newNodes, +/** + * @brief MainWindow::slotRandomErdosRenyi + * @param newNodes + * @param model + * @param edges + * @param eprob + * @param mode + * @param diag + * Calls activeGraph.slotRandomErdosRenyi () to create a symmetric network + * Edge existance is controlled by a user specified possibility. + */ +void MainWindow::slotRandomErdosRenyi( const int newNodes, const QString model, const int edges, const float eprob, const QString mode, const bool diag) { - qDebug() << "MW::createRandomNetErdos()"; + qDebug() << "MW::slotRandomErdosRenyi()"; - statusMessage( "Erasing any existing network. "); - initNet(); + statusMessage( tr("Erasing any existing network.")); - statusMessage( tr("Creating random network. Please wait... ") ); + initNet(); + statusMessage( tr("Creating Erdos-Renyi Random Network. Please wait... ") ); - if (showProgressBarAct->isChecked() && newNodes > 500 && eprob > 0.06){ - progressDialog= new QProgressDialog( - "Creating random network. \n " - " Please wait (or disable me from Options > View > ProgressBar, next time ;)).", - "Cancel", 0, newNodes+newNodes, this); - progressDialog -> setWindowModality(Qt::WindowModal); - connect( &activeGraph, SIGNAL( updateProgressDialog(int) ), progressDialog, SLOT(setValue(int) ) ) ; - progressDialog->setMinimumDuration(0); - } + progressMsg = "Creating Erdos-Renyi Random Network. \n " + " Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar( (edges != 0 ? edges:newNodes), progressMsg ); + appSettings["randomErdosEdgeProbability"] = QString::number(eprob); - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - activeGraph.createRandomNetErdos ( newNodes, + activeGraph.randomNetErdosCreate ( newNodes, model, edges, eprob, mode, diag); - QApplication::restoreOverrideCursor(); - - if (showProgressBarAct->isChecked() && newNodes > 500 && eprob > 0.06) - progressDialog->deleteLater(); + destroyProgressBar( (edges != 0 ? edges:newNodes) ); fileLoaded=false; - graphChanged(); + setWindowTitle("Untitled Erdos-Renyi random network"); - setWindowTitle("Untitled"); double threshold = log(newNodes)/newNodes; - //float avGraphDistance=activeGraph.averageGraphDistance(); - - float clucof=activeGraph.clusteringCoefficient(); + //float clucof=activeGraph.clusteringCoefficient(); if ( (eprob ) > threshold ) QMessageBox::information( this, - "New Random Network", + "New Erdos-Renyi Random Network", tr("Random network created. \n")+ - tr("\nNodes: ")+ QString::number(activeNodes())+ - tr("\nEdges: ")+ QString::number( (mode == "graph") ? activeEdges()/2.0 : activeEdges() ) + //tr("\nAverage path length: ") + QString::number(avGraphDistance)+ - tr("\nClustering coefficient: ")+QString::number(clucof)+ + //tr("\nClustering coefficient: ")+QString::number(clucof)+ tr("\n\nOn the average, edges should be ") + QString::number( eprob * newNodes*(newNodes-1)) + tr("\nThis graph is almost surely connected because: \nprobability > ln(n)/n, that is: \n") @@ -4296,139 +5587,70 @@ void MainWindow::createRandomNetErdos( const int newNodes, else QMessageBox::information( this, - "New Random Network", + "New Erdos-Renyi Random Network", tr("Random network created. \n")+ - tr("\nNodes: ")+ QString::number(activeNodes())+ - tr("\nEdges: ")+ QString::number( (mode == "graph") ? activeEdges()/2.0 : activeEdges() )+ //tr("\nAverage path length: ") + QString::number(avGraphDistance)+ - tr("\nClustering coefficient: ")+QString::number(clucof)+ + //tr("\nClustering coefficient: ")+QString::number(clucof)+ tr("\n\nOn the average, edges should be ") + QString::number(eprob * newNodes*(newNodes-1)) + tr("\nThis graph is almost surely not connected because: \nprobability < ln(n)/n, that is: \n") + QString::number(eprob)+ " smaller than "+ QString::number(threshold) , "OK",0); - statusMessage( "Random network created. "); - -} - - - - - - -/** - Creates a pseudo-random network where every node has the same degree -*/ -void MainWindow::slotCreateRegularRandomNetwork(){ - bool ok; - statusMessage( "Creating a pseudo-random network where each node has the same degree... "); - int newNodes= QInputDialog::getInt( - this, - tr("Create k-regular network"), - tr("This will create a network with nodes of the same degree d.") - + tr("\nPlease enter the number of nodes:"), - 100, 1, maxNodes, 1, &ok - ) ; - if (!ok) { - statusMessage( "You did not enter an integer. Aborting."); - return; - } - int degree = QInputDialog::getInt( - this, - tr("Create k-regular network..."), - tr("Now, select an even number d. \nThis will be the degree (number of edges) of each node:"), - 2, 2, newNodes-1, 2, &ok - ); - - if ( (degree% 2)==1 ) { - QMessageBox::critical( - this, - "Error", - tr(" Sorry. I cannot create such a network. Degree must be even number"), - "OK",0 ); - return; - } - statusMessage( "Erasing any existing network. "); - initNet(); - statusMessage( "Creating a pseudo-random network where each node has the same degree... "); - - if (showProgressBarAct->isChecked() && newNodes > 300){ - progressDialog= new QProgressDialog ( - "Creating random network. Please wait (or disable me from Options > View > ProgressBar, next time ;)).", "Cancel", 0, (int) (newNodes+newNodes), this); - progressDialog -> setWindowModality(Qt::WindowModal); - connect( &activeGraph, SIGNAL( updateProgressDialog(int) ), progressDialog, SLOT(setValue(int) ) ) ; - progressDialog->setMinimumDuration(0); - } - - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - - activeGraph.createSameDegreeRandomNetwork (newNodes, degree); - - QApplication::restoreOverrideCursor(); - - if (showProgressBarAct->isChecked() && newNodes > 300) - progressDialog->deleteLater(); - - fileLoaded=false; - - graphChanged(); - setWindowTitle("Untitled"); - statusMessage( "Uniform random network created: " - +QString::number(activeNodes())+" Nodes, " - +QString::number( activeEdges())+" Edges"); + statusMessage( tr("Erdos-Renyi Random Network created. ") ) ; } -void MainWindow::slotCreateRandomGaussian(){ - graphChanged(); - -} - -void MainWindow::slotCreateRandomScaleFree() { - qDebug() << "MW;:slotCreateRandomScaleFree()"; +/** + * @brief MainWindow::slotRandomScaleFreeDialog + */ +void MainWindow::slotRandomScaleFreeDialog() { + qDebug() << "MW;:slotRandomScaleFreeDialog()"; m_randScaleFreeDialog = new RandScaleFreeDialog(this); connect( m_randScaleFreeDialog, &RandScaleFreeDialog::userChoices, - this, &MainWindow::createScaleFreeNetwork); + this, &MainWindow::slotRandomScaleFree); m_randScaleFreeDialog->exec(); } -void MainWindow::createScaleFreeNetwork ( const int &nodes, +/** + * @brief MainWindow::slotRandomScaleFree + * @param nodes + * @param power + * @param initialNodes + * @param edgesPerStep + * @param zeroAppeal + * @param mode + */ +void MainWindow::slotRandomScaleFree ( const int &newNodes, const int &power, const int &initialNodes, const int &edgesPerStep, const float &zeroAppeal, const QString &mode) { - qDebug() << "MW;:createScaleFreeNetwork()"; + qDebug() << "MW;:slotRandomScaleFree()"; statusMessage( tr("Erasing any existing network. ")); initNet(); - statusMessage( tr("Creating small world network. Please wait...")); double x0=scene->width()/2.0; double y0=scene->height()/2.0; - double radius=(graphicsWidget->height()/2.0)-50; //pixels + double radius=(graphicsWidget->height()/2.0)-50; - if (showProgressBarAct->isChecked() && nodes > 300){ - progressDialog= new QProgressDialog( - tr("Creating random network. Please wait \n (or disable me from Options > View > ProgressBar, next time )."), - "Cancel", 0, (int) (2* nodes), this); - progressDialog -> setWindowModality(Qt::WindowModal); - connect( &activeGraph, SIGNAL( updateProgressDialog(int) ), progressDialog, SLOT(setValue(int) ) ) ; - progressDialog->setMinimumDuration(0); - } - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + statusMessage( tr("Creating Scale-Free Random Network. Please wait...")); + progressMsg = "Creating Scale-Free Random Network. \n" + "Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar(newNodes, progressMsg ); - activeGraph.createRandomNetScaleFree( nodes, + activeGraph.randomNetScaleFreeCreate( newNodes, power, initialNodes, edgesPerStep, @@ -4438,164 +5660,226 @@ void MainWindow::createScaleFreeNetwork ( const int &nodes, y0, radius); - QApplication::restoreOverrideCursor(); - - if (showProgressBarAct->isChecked() && nodes > 300 ) - progressDialog->deleteLater(); + destroyProgressBar(newNodes); fileLoaded=false; - graphChanged(); - setWindowTitle("Untitled"); - statusMessage( tr("Scale-free random network created: ") - + QString::number(activeNodes()) - + " nodes, "+QString::number( activeEdges())+" edges"); - //float avGraphDistance=activeGraph.averageGraphDistance(); - float clucof=activeGraph.clusteringCoefficient(); + setWindowTitle("Untitled scale-free network"); + + //float avGraphDistance=activeGraph.distanceGraphAverage(); + //float clucof=activeGraph.clusteringCoefficient(); QMessageBox::information(this, "New scale-free network", - tr("Scale-free random network created.\n")+ - tr("\nNodes: ")+ QString::number(activeNodes())+ - tr("\nEdges: ") - + QString::number( (mode == "graph" ) ? activeEdges()/2.0 : activeEdges()) + tr("Scale-free random network created.\n") +// +tr("\nNodes: ")+ QString::number(nodeCount)+ +// tr("\nEdges: ") + QString::number( edgeCount ) //+ tr("\nAverage path length: ") + QString::number(avGraphDistance) - + tr("\nClustering coefficient: ")+QString::number(clucof) + //+ tr("\nClustering coefficient: ")+QString::number(clucof) , "OK",0); + statusMessage( tr("Scale-Free Random Network created: ") ); + } -void MainWindow::slotCreateRandomSmallWorld() + +/** + * @brief MainWindow::slotRandomSmallWorldDialog + */ +void MainWindow::slotRandomSmallWorldDialog() { - qDebug() << "MW;:slotCreateRandomSmallWorld()"; + qDebug() << "MW::slotRandomSmallWorldDialog()"; m_randSmallWorldDialog = new RandSmallWorldDialog(this); connect( m_randSmallWorldDialog, &RandSmallWorldDialog::userChoices, - this, &MainWindow::createSmallWorldNetwork); + this, &MainWindow::slotRandomSmallWorld); m_randSmallWorldDialog->exec(); } -void MainWindow::createSmallWorldNetwork (const int &nodes, + +/** + * @brief MainWindow::slotrandomSmallWorldNetwork + * @param nodes + * @param degree + * @param beta + * @param mode + * @param diag + */ +void MainWindow::slotRandomSmallWorld(const int &newNodes, const int °ree, const float &beta, const QString &mode, const bool &diag) { Q_UNUSED(diag); - qDebug() << "MW;:createSmallWorldNetwork()"; + qDebug() << "MW::slotRandomSmallWorld()"; statusMessage( tr("Erasing any existing network. ")); initNet(); - statusMessage( tr("Creating small world network. Please wait...")); double x0=scene->width()/2.0; double y0=scene->height()/2.0; double radius=(graphicsWidget->height()/2.0)-50; //pixels - if (showProgressBarAct->isChecked() && nodes > 300){ - progressDialog= new QProgressDialog( - tr("Creating random network. Please wait \n (or disable me from Options > View > ProgressBar, next time )."), - "Cancel", 0, (int) (2* nodes), this); - progressDialog -> setWindowModality(Qt::WindowModal); - connect( &activeGraph, SIGNAL( updateProgressDialog(int) ), progressDialog, SLOT(setValue(int) ) ) ; - progressDialog->setMinimumDuration(0); - } - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - activeGraph.createRandomNetSmallWorld(nodes, degree, beta, x0, y0, radius); - activeGraph.symmetrize(); - QApplication::restoreOverrideCursor(); + statusMessage( tr("Creating Small-World Random Network. Please wait...")); + progressMsg = "Creating Small-World Random Network. \n" + "Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar(newNodes, progressMsg ); + + activeGraph.randomNetSmallWorldCreate(newNodes, degree, beta, mode, x0, y0, radius); - if (showProgressBarAct->isChecked() && nodes > 300 ) - progressDialog->deleteLater(); + destroyProgressBar(newNodes); fileLoaded=false; - graphChanged(); - setWindowTitle("Untitled"); - statusMessage( tr("Small world random network created: ")+QString::number(activeNodes())+" nodes, "+QString::number( activeEdges())+" edges"); - //float avGraphDistance=activeGraph.averageGraphDistance(); - float clucof=activeGraph.clusteringCoefficient(); - QMessageBox::information(this, "New Small World", - tr("Small world network created.\n")+ - tr("\nNodes: ")+ QString::number(activeNodes())+ - tr("\nEdges: ") - + QString::number( (mode == "graph" ) ? activeEdges()/2.0 : activeEdges()) + setWindowTitle("Untitled small-world network"); + + //float avGraphDistance=activeGraph.distanceGraphAverage(); + //float clucof=activeGraph.clusteringCoefficient(); + QMessageBox::information(this, "New Small World network", + tr("Small world network created.\n") +// +tr("\nNodes: ")+ QString::number(nodeCount)+ +// tr("\nEdges: ") + QString::number( edgeCount ) //+ tr("\nAverage path length: ") + QString::number(avGraphDistance) - + tr("\nClustering coefficient: ")+QString::number(clucof) + //+ tr("\nClustering coefficient: ")+QString::number(clucof) , "OK",0); + + statusMessage( tr("Small World Random Network created. ") ); } + /** - Creates a lattice network, i.e. a connected network where every node - has the same degree and is Edgeed with its neighborhood. -*/ -void MainWindow::slotCreateRandomRingLattice(){ + * @brief MainWindow::slotRandomRegularNetwork + * Creates a pseudo-random k-regular network where every node has the same degree + */ +void MainWindow::slotRandomRegularNetwork(){ bool ok; - statusMessage( "You have selected to create a ring lattice network. "); - int newNodes=( QInputDialog::getInt( + + statusMessage( "Creating a pseudo-random network where each node has the same degree... "); + int newNodes= QInputDialog::getInt( this, - tr("Create ring lattice"), - tr("This will create a ring lattice network, where each node has degree d:\n d/2 edges to the right and d/2 to the left.\n Please enter the number of nodes you want:"), - 100, 4, maxNodes, 1, &ok ) ) ; + tr("Create d-regular network"), + tr("This will create a network with nodes of the same degree d.") + + tr("\nPlease enter the number of nodes:"), + 100, 1, maxNodes, 1, &ok + ) ; if (!ok) { statusMessage( "You did not enter an integer. Aborting."); return; } int degree = QInputDialog::getInt( this, - tr("Create ring lattice..."), - tr("Now, enter an even number d. \nThis is the total number of edges each new node will have:"), - 2, 2, newNodes-1, 2, &ok); + tr("Create d-regular network..."), + tr("Now, select an even number d. \n" + "This will be the degree (number of edges) of each node:"), + 2, 2, newNodes-1, 2, &ok + ); + if ( (degree% 2)==1 ) { - QMessageBox::critical(this, "Error",tr(" Sorry. I cannot create such a network. Degree must be even number"), "OK",0); - return; + QMessageBox::critical( + this, + "Error", + tr(" Sorry. I cannot create such a network. Degree must be even number"), + "OK",0 ); + return; + } + statusMessage( "Erasing any existing network. "); + initNet(); + statusMessage( "Creating a pseudo-random d-regular network where each node " + "has the same degree... "); + + progressMsg = "Creating pseudo-random d-regular network. \n" + "Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar(newNodes, progressMsg ); + + activeGraph.randomNetSameDegreeCreate (newNodes,degree); + + destroyProgressBar(newNodes); + + fileLoaded=false; + + setWindowTitle("Untitled d-regular network"); + statusMessage( tr( "d-regular network created. " ) ); + +} + + + + +void MainWindow::slotRandomGaussian(){ + slotNetworkChanged(); + +} + + +/** + * @brief MainWindow::slotRandomRingLattice + * Creates a lattice network, i.e. a connected network where every node + has the same degree and is connected with its neighborhood. + */ +void MainWindow::slotRandomRingLattice(){ + bool ok; + statusMessage( "You have selected to create a ring lattice network. "); + int newNodes=( QInputDialog::getInt( + this, + tr("Create ring lattice"), + tr("This will create a ring lattice network, " + "where each node has degree d:\n d/2 edges to the right " + "and d/2 to the left.\n " + "Please enter the number of nodes you want:"), + 100, 4, maxNodes, 1, &ok ) ) ; + if (!ok) { + statusMessage( "You did not enter an integer. Aborting."); + return; + } + int degree = QInputDialog::getInt( + this, + tr("Create ring lattice..."), + tr("Now, enter an even number d. \n" + "This is the total number of edges each new node will have:"), + 2, 2, newNodes-1, 2, &ok); + if ( (degree% 2)==1 ) { + QMessageBox::critical(this, "Error",tr(" Sorry. I cannot create such a network. " + "Degree must be even number"), "OK",0); + return; } statusMessage( "Erasing any existing network. "); initNet(); - statusMessage( "Creating ring lattice network. Please wait..."); + double x0=scene->width()/2.0; double y0=scene->height()/2.0; double radius=(graphicsWidget->height()/2.0)-50; //pixels - if (showProgressBarAct->isChecked() && newNodes > 300){ - progressDialog= new QProgressDialog("Creating random network. Please wait (or disable me from Options > View > ProgressBar, next time ;)).", "Cancel", 0, (int) (newNodes+newNodes), this); - progressDialog -> setWindowModality(Qt::WindowModal); - connect( &activeGraph, SIGNAL( updateProgressDialog(int) ), progressDialog, SLOT(setValue(int) ) ) ; - progressDialog->setMinimumDuration(0); - } - - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - - activeGraph.createRandomNetRingLattice(newNodes, degree, x0, y0, radius ); + statusMessage( "Creating ring lattice network. Please wait..."); + progressMsg = "Creating ring-lattice network. \n" + "Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar(newNodes, progressMsg ); - QApplication::restoreOverrideCursor(); + activeGraph.randomNetRingLatticeCreate(newNodes, degree, x0, y0, radius, true ); - if (showProgressBarAct->isChecked() && newNodes > 300) - progressDialog->deleteLater(); + destroyProgressBar(newNodes); fileLoaded=false; - // graphChanged(); - - statusMessage( "Ring lattice random network created: "+QString::number(activeNodes())+" nodes, "+QString::number( activeEdges())+" edges"); - - setWindowTitle("Untitled"); - //float avGraphDistance=activeGraph.averageGraphDistance(); + setWindowTitle("Untitled ring-lattice network"); + //float avGraphDistance=activeGraph.distanceGraphAverage(); //float clucof=activeGraph.clusteringCoefficient(); - QMessageBox::information(this, "Ring Lattice", - tr("Ring lattice network created.\n")+ - tr("\nNodes: ")+ QString::number(activeNodes())+ - tr("\nEdges: ")+ QString::number( activeEdges()/2.0) + QMessageBox::information(this, "New Ring Lattice", + tr("Ring lattice network created.\n") +// +tr("\nNodes: ")+ QString::number(activeNodes())+ +// tr("\nEdges: ")+ QString::number( activeEdges() ) // + tr("\nAverage path length: ") + QString::number(avGraphDistance) //+ tr("\nClustering coefficient: ")+QString::number(clucof) , "OK",0); + + statusMessage( tr("Ring lattice random network created: " )); } @@ -4605,13 +5889,12 @@ void MainWindow::slotCreateRandomRingLattice(){ /** -* Shows a dialog from where the user -* creates a new network by crawling a given website -*/ -void MainWindow::slotShowWebCrawlerDialog() { - qDebug () << "MW: slotShowWebCrawlerDialog() - sending canvasWidth and Height"; - activeGraph.setCanvasDimensions(graphicsWidget->width(), graphicsWidget->height()); - + * @brief MainWindow::slotNetworkWebCrawlerDialog + * Shows a dialog where enters a website url + * and the app creates a new network by crawling it + */ +void MainWindow::slotNetworkWebCrawlerDialog() { + qDebug () << "MW: slotNetworkWebCrawlerDialog() - canvas Width & Height already sent"; m_WebCrawlerDialog.exec() ; } @@ -4621,179 +5904,147 @@ void MainWindow::slotShowWebCrawlerDialog() { /** -* Called from m_WebCrawlerDialog -* Clears the loaded network (saving if needed) -* then passes parameters to webCrawl of ActiveGraph class. -*/ -void MainWindow::slotWebCrawl ( QString seed, int maxNodes, int maxRecursion, + * @brief MainWindow::slotNetworkWebCrawler + * Called from m_WebCrawlerDialog + * Clears the loaded network (saving if needed) then passes parameters to + * Graph::webCrawl function + * @param seed + * @param maxNodes + * @param maxRecursion + * @param extLinks + * @param intLinks + */ +void MainWindow::slotNetworkWebCrawler ( QString seed, int maxNodes, int maxRecursion, bool extLinks, bool intLinks) { - this->slotFileClose(); + this->slotNetworkClose(); activeGraph.webCrawl( seed, maxNodes, maxRecursion, extLinks, intLinks) ; } -/** - Calls GW: findNode() to find a node by its number or label. The node is then marked. -*/ -void MainWindow::slotFindNode(){ - qDebug ("MW: slotFindNode()"); - if (!fileLoaded && !networkModified ) { - QMessageBox::critical( this, tr("Find Node"), - tr("No nodes present! \nLoad a network file first or create some nodes..."), - tr("OK"),0 ); - statusMessage( QString(tr("Nothing to find!")) ); - return; - } - - if ( markedNodesExist ) { // if a node has been already marked - graphicsWidget->setMarkedNode(""); // call setMarkedNode to just unmark it. - markedNodesExist=false; - statusMessage( tr("Node unmarked.") ); - return; // and return to MW - } - - bool ok=false; - QString nodeText = QInputDialog::getText(this, tr("Find Node"), - tr("Enter node label or node number:"), - QLineEdit::Normal,QString::null, &ok ); - if (!ok) { - statusMessage( tr("Find node operation cancelled.") ); - return; - } - - else { - if ( graphicsWidget->setMarkedNode(nodeText) ) { - markedNodesExist=true; - statusMessage( tr("Node found and marked. Press Ctrl+F again to unmark...") ); - } - else { - QMessageBox::information(this, tr("Find Node"), - tr("Sorry. There is no such node in this network. \n Try again."), "OK",0); - } - } -} - - - /** -* A slot activated when something has been changed in the graph. - Makes the fileSave icon active and refreshes any LCD values. - Also called from graphicsWidget. -*/ -void MainWindow::graphChanged(){ - qDebug("MW: graphChanged"); + * @brief MainWindow::slotNetworkChanged + * Activated when something has been changed in the graph. + * Makes the networkSave icon active and refreshes any LCD values. + * Also called from activeGraph and graphicsWidget. + */ +void MainWindow::slotNetworkChanged(){ + qDebug("MW: slotNetworkChanged"); networkModified=true; - fileSave->setIcon(QIcon(":/images/save.png")); - fileSave->setEnabled(true); + networkSave->setIcon(QIcon(":/images/save.png")); + networkSave->setEnabled(true); nodesLCD->display(activeGraph.vertices()); + if (activeGraph.isUndirected()) { + edgesLCD->setStatusTip(tr("Shows the total number of undirected edges in the network.")); + edgesLCD->setToolTip(tr("The total number of undirected edges in the network.")); + networkLabel->setStatusTip(tr("Undirected data mode. Toggle the menu option Edit -> Edges -> Undirected Edges to change it")); + networkLabel->setToolTip(tr("The loaded network, if any, is undirected and \n" + "any edge you add between nodes will be undirected.\n" + "If you want to work with directed edges and/or \n" + "transform the loaded network (if any) to directed \n" + "disable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + networkLabel->setWhatsThis(tr("The loaded network, if any, is undirected and \n" + "any edge you add between nodes will be undirected.\n" + "If you want to work with directed edges and/or \n" + "transform the loaded network (if any) to directed \n" + "disable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + + networkLabel-> setText ("Network Type: Undirected"); + labelEdgesLCD->setText(tr("Total Edges")); + editEdgeUndirectedAllAct->setChecked(true); + } + else { + edgesLCD->setStatusTip(tr("Shows the total number of directed edges in the network.")); + edgesLCD->setToolTip(tr("The total number of directed edges in the network.")); + networkLabel->setStatusTip(tr("Directed data mode. Toggle the menu option Edit -> Edges -> Undirected Edges to change it")); + networkLabel->setToolTip(tr("The loaded network, if any, is directed and \n" + "any link you add between nodes will be a directed arc.\n" + "If you want to work with undirected edges and/or \n" + "transform the loaded network (if any) to undirected \n" + "enable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + networkLabel->setWhatsThis(tr("The loaded network, if any, is directed and \n" + "any link you add between nodes will be a directed arc.\n" + "If you want to work with undirected edges and/or \n" + "transform the loaded network (if any) to undirected \n" + "enable the option Edit -> Edges -> Undirected \n" + "or press CTRL+E+U")); + + networkLabel-> setText ("Network Type: Directed"); + labelEdgesLCD->setText(tr("Total Arcs")); + editEdgeUndirectedAllAct->setChecked(false); + } edgesLCD->display(activeEdges()); densityLCD->display( activeGraph.density() ); } -void MainWindow::slotSelectAll(){ - qDebug() << "MainWindow::slotSelectAll()"; - graphicsWidget->selectAll(); - statusMessage( QString(tr("Selected nodes: %1") ) - .arg( selectedNodes().count() ) ); -} -void MainWindow::slotSelectNone(){ - qDebug() << "MainWindow::slotSelectNone()"; - graphicsWidget->selectNone(); - statusMessage( QString(tr("Selection cleared") ) ); -} /** - Popups a context menu with some options when the user right-clicks on a node -*/ -void MainWindow::openNodeContextMenu() { - clickedJimNumber=clickedJim->nodeNumber(); - qDebug("MW: openNodeContextMenu() for node %i at %i, %i", - clickedJimNumber, QCursor::pos().x(), QCursor::pos().y()); - - QMenu *nodeContextMenu = new QMenu(QString::number(clickedJimNumber), this); - Q_CHECK_PTR( nodeContextMenu ); //displays "out of memory" if needed - if ( selectedNodes().count() == 1) { - nodeContextMenu -> addAction( tr("## NODE ") + QString::number(clickedJimNumber) + " ## "); - } - else { - nodeContextMenu -> addAction( tr("## NODE ") + QString::number(clickedJimNumber) + " ## " + tr(" (selected nodes: ") + QString::number (selectedNodes().count() ) + ")"); - } - - nodeContextMenu -> addSeparator(); - nodeContextMenu -> addAction(addEdgeAct); - nodeContextMenu -> addAction(removeNodeAct ); - nodeContextMenu -> addAction(propertiesNodeAct ); - //QCursor::pos() is good only for menus not related with node coordinates - nodeContextMenu -> exec(QCursor::pos() ); - delete nodeContextMenu; - clickedJimNumber=-1; //undo node selection -} - - - -/** - Popups a context menu with some options when the user right-clicks on an Edge -*/ -void MainWindow::openEdgeContextMenu() { - int source=clickedEdge->sourceNodeNumber(); - int target=clickedEdge->targetNodeNumber(); - qDebug("MW: openEdgeContextMenu() for edge %i-%i at %i, %i",source, target, QCursor::pos().x(), QCursor::pos().y()); - QString edgeName=QString::number(source)+QString("->")+QString::number(target); - //make the menu - QMenu *edgeContextMenu = new QMenu(edgeName, this); - edgeContextMenu -> addAction( "## EDGE " + edgeName + " ## "); - edgeContextMenu -> addSeparator(); - edgeContextMenu -> addAction( removeEdgeAct ); - edgeContextMenu -> addAction( changeEdgeWeightAct ); - edgeContextMenu -> addAction( changeEdgeColorAct ); - edgeContextMenu -> exec(QCursor::pos() ); - delete edgeContextMenu; -} - -/** - Popups a context menu with some options when the user right-clicks on the scene -*/ -void MainWindow::openContextMenu( const QPointF &mPos) { + * @brief MainWindow::slotEditOpenContextMenu + * Popups a context menu with some options when the user right-clicks on the scene + * @param mPos + */ +void MainWindow::slotEditOpenContextMenu( const QPointF &mPos) { cursorPosGW=mPos; QMenu *contextMenu = new QMenu(" Menu",this); Q_CHECK_PTR( contextMenu ); //displays "out of memory" if needed - + int nodeCount = selectedNodes().count(); contextMenu -> addAction( "## Selected nodes: " - + QString::number( selectedNodes().count() ) + " ## "); + + QString::number( nodeCount ) + " ## "); contextMenu -> addSeparator(); - contextMenu -> addAction( addNodeAct ); - - if (selectedNodes().count()) { - contextMenu -> addAction(propertiesNodeAct ); + if (nodeCount > 0) { + contextMenu -> addAction(editNodePropertiesAct ); + contextMenu -> addSeparator(); + contextMenu -> addAction(editNodeRemoveAct ); + if (nodeCount > 1 ){ + editNodeRemoveAct->setText(tr("Remove ") + + QString::number(nodeCount) + + tr(" nodes")); + } + else { + editNodeRemoveAct->setText(tr("Remove ") + + QString::number(nodeCount) + + tr(" node")); + } + contextMenu -> addSeparator(); } - contextMenu -> addAction( addEdgeAct ); + contextMenu -> addAction( editNodeAddAct ); + contextMenu -> addSeparator(); + contextMenu -> addAction( editEdgeAddAct ); + contextMenu -> addSeparator(); QMenu *options=new QMenu("Options", this); contextMenu -> addMenu(options ); + options -> addAction (openSettingsAct ); + options -> addSeparator(); + options -> addAction (editNodeSizeAllAct ); + options -> addAction (editNodeShapeAll ); + options -> addAction (editNodeColorAll ); + options -> addAction (optionsNodeNumbersVisibilityAct); + options -> addAction (optionsNodeLabelsVisibilityAct); + options -> addSeparator(); + options -> addAction (editEdgeColorAllAct ); + options -> addSeparator(); options -> addAction (changeBackColorAct ); options -> addAction (backgroundImageAct ); - options -> addAction (changeAllNodesSizeAct ); - options -> addAction (changeAllNodesShapeAct ); - options -> addAction (changeAllNodesColorAct ); - options -> addAction (changeAllEdgesColorAct ); - options -> addAction (displayNodeNumbersAct); - options -> addAction (displayNodeLabelsAct); + //QCursor::pos() is good only for menus not related with node coordinates contextMenu -> exec(QCursor::pos() ); delete contextMenu; @@ -4802,98 +6053,139 @@ void MainWindow::openContextMenu( const QPointF &mPos) { - +/** + * @brief MainWindow::selectedNodes + * Returns a QList of all selected nodes + * @return + */ QList MainWindow::selectedNodes() { return graphicsWidget->selectedItems(); } +/** + * @brief MainWindow::slotEditClickOnEmptySpace + * Called from GW when the user clicks on empty space. + */ +void MainWindow::slotEditClickOnEmptySpace() { + selectedNodeLCD->display (0); + inDegreeLCD->display (0); + outDegreeLCD->display (0); + clucofLCD->display(0); + nodeClicked = false; +} + +/** + * @brief MainWindow::slotEditNodeSelectAll + */ +void MainWindow::slotEditNodeSelectAll(){ + qDebug() << "MainWindow::slotEditNodeSelectAll()"; + graphicsWidget->selectAll(); + statusMessage( QString(tr("Selected nodes: %1") ) + .arg( selectedNodes().count() ) ); +} /** -* When the user clicks on a node, displays some information about it on the status bar. -*/ -void MainWindow::nodeInfoStatusBar ( Node *jim) { - qDebug ("MW: NodeInfoStatusBar()"); - edgeClicked=false; - nodeClicked=true; - clickedJim=jim; - clickedJimNumber=clickedJim->nodeNumber(); - int inDegree=activeGraph.inDegree(clickedJimNumber); - int outDegree=activeGraph.outDegree(clickedJimNumber); - selectedNodeLCD->display (clickedJimNumber); - inDegreeLCD->display (inDegree); - outDegreeLCD->display (outDegree); - if (activeGraph.vertices() < 500) - clucofLCD->display(activeGraph.localClusteringCoefficient(clickedJimNumber)); + * @brief MainWindow::slotEditNodeSelectNone + */ +void MainWindow::slotEditNodeSelectNone(){ + qDebug() << "MainWindow::slotEditNodeSelectNone()"; + graphicsWidget->selectNone(); + statusMessage( QString(tr("Selection cleared") ) ); +} - statusMessage( QString(tr("(%1, %2); Node %3, label %4 - " - "In-Degree: %5, Out-Degree: %6")).arg( ceil( clickedJim->x() ) ) - .arg( ceil( clickedJim->y() )).arg( clickedJimNumber ).arg( clickedJim->labelText() ) - .arg(inDegree).arg(outDegree) ); + +/** + * @brief MainWindow::slotEditNodeAdd + * Calls Graph::vertexCreate method to add a new RANDOM node into the activeGraph. + * Called when "Add Node" button is clicked on the Main Window. + */ +void MainWindow::slotEditNodeAdd() { + qDebug() << "MW::slotEditNodeAdd() "; + // minus a screen edge offset... + activeGraph.vertexCreate (-1); + statusMessage( tr("New node (numbered %1) added.") + .arg(activeGraph.vertexLastNumber()) ); } /** -* When the user clicks on an Edge, displays some information about it on the status bar. -*/ -void MainWindow::edgeInfoStatusBar (Edge* edge) { - clickedEdge=edge; - edgeClicked=true; - nodeClicked=false; + * @brief MainWindow::slotEditNodeAddWithMouse + * Called by GW when user double-clicks at p to add a new node + * Calls Graph::vertexCreate method to add the new vertex into the activeGraph. + * @param p + */ +void MainWindow::slotEditNodeAddWithMouse( const QPointF &p) { + qDebug()<< "MW: slotEditNodeAddWithMouse(). Calling activeGraph::vertexCreate()"; + activeGraph.vertexCreate(p); + statusMessage( tr("New node (numbered %1) added.").arg(activeGraph.vertexLastNumber()) ); +} + - if (edge->isReciprocal()) { - float outbound = activeGraph.hasArc - (edge->sourceNodeNumber(), edge->targetNodeNumber()); - float inbound = activeGraph.hasArc - (edge->targetNodeNumber(), edge->sourceNodeNumber()); - if (outbound==inbound) - statusMessage( QString - (tr("Symmetric edge %1 <--> %2 of weight %3 has been selected. " - "Click again to unselect it.")) - .arg( edge->sourceNodeNumber() ).arg(edge->targetNodeNumber()) - .arg(edge->weight()) ) ; - else - statusMessage( QString - (tr("Arc %1 --> %2 of weight %3 " - " and Arc %4 --> %5 of weight %6" - " have been selected. " - "Click again to unselect them.")) - .arg(edge->sourceNodeNumber() ) - .arg(edge->targetNodeNumber()) - .arg(outbound) - .arg( edge->targetNodeNumber() ) - .arg(edge->sourceNodeNumber()) - .arg(inbound) ) ; +/** + * @brief MainWindow::slotEditNodeFind + * Calls GW::setMarkedNode() to find a node by its number or label. + * The node is then marked. + */ +void MainWindow::slotEditNodeFind(){ + qDebug ("MW: slotEditNodeFind()"); + if (!fileLoaded && !networkModified ) { + QMessageBox::critical( this, tr("Find Node"), + tr("No nodes present! \nLoad a network file first or create some nodes..."), + tr("OK"),0 ); + statusMessage( QString(tr("Nothing to find!")) ); + return; } - else { - statusMessage( QString(tr("Arc %1 --> %2 of weight %3 has been selected. " - "Click again to unselect it.")) - .arg( edge->sourceNodeNumber() ).arg(edge->targetNodeNumber()) - .arg(edge->weight()) ) ; + + if ( markedNodesExist ) { // if a node has been already marked + graphicsWidget->setMarkedNode(""); // call setMarkedNode to just unmark it. + markedNodesExist=false; + statusMessage( tr("Node unmarked.") ); + return; // and return to MW } -} + bool ok=false; + QString nodeText = QInputDialog::getText(this, tr("Find Node"), + tr("Enter node label or node number:"), + QLineEdit::Normal,QString::null, &ok ); + if (!ok) { + statusMessage( tr("Find node operation cancelled.") ); + return; + } + else { + if ( graphicsWidget->setMarkedNode(nodeText) ) { + markedNodesExist=true; + statusMessage( tr("Node found and marked. Press Ctrl+F again to unmark...") ); + } + else { + QMessageBox::information(this, tr("Find Node"), + tr("Sorry. There is no such node in this network. \n Try again."), "OK",0); + } + } +} /** -* Deletes a node and the attached objects (edges, etc). -* It deletes clickedJim (signal from GraphicsView or set by another function) -* or else asks for a nodeNumber to remove. The nodeNumber is doomedJim. - Called from nodeContextMenu -*/ -void MainWindow::slotRemoveNode() { - qDebug() << "MW: slotRemoveNode()"; + * @brief MainWindow::slotEditNodeRemove + * Deletes a node and the attached objects (edges, etc). + * If user has clicked on a node (signaled from GW or set by another function) + * it deletes it + * Else it asks for a nodeNumber to remove. The nodeNumber is doomedJim. + * Called from nodeContextMenu + */ +void MainWindow::slotEditNodeRemove() { + qDebug() << "MW: slotEditNodeRemove()"; if (!activeGraph.vertices()) { QMessageBox::critical( this, @@ -4910,46 +6202,74 @@ void MainWindow::slotRemoveNode() { "This a network with more than 1 relations. If you remove " "a node from the active relation, and then ask me to go " "to the previous or the next relation, then I would crash " - "because I would try to display edges from a delete node." - "You can only add nodes in multirelational networks."), + "because I would try to display edges from a deleted node." + "You cannot remove nodes in multirelational networks."), "OK",0); statusMessage( tr("Nothing to remove.") ); return; } - int doomedJim=-1, min=-1, max=-1; - bool ok=false; - min = activeGraph.firstVertexNumber(); - max = activeGraph.lastVertexNumber(); - qDebug("MW: min is %i and max is %i", min, max); - if (min==-1 || max==-1 ) { - qDebug("ERROR in finding min max nodeNumbers. Abort"); - return; - } - else if (nodeClicked && clickedJimNumber >= 0 && clickedJimNumber<= max ) { - doomedJim=clickedJimNumber ; + // if there are already multiple nodes selected, erase them + int nodeCount = selectedNodes().count(); + if ( nodeCount > 1) { + int removeCounter = 0; + qDebug() << "MW: removeNode() multiple selected to remove"; + foreach (QGraphicsItem *item, selectedNodes() ) { + if ( (clickedNode = qgraphicsitem_cast(item) )) { + activeGraph.vertexRemove(clickedNode->nodeNumber()); + ++removeCounter ; + } + } + editNodeRemoveAct->setText(tr("Remove Node")); + statusMessage( tr("Removed ") + nodeCount + tr(" nodes. Ready. ") ); } - else if (!nodeClicked ) { - doomedJim = QInputDialog::getInt(this,"Remove node",tr("Choose a node to remove between (" - + QString::number(min).toLatin1()+"..."+QString::number(max).toLatin1()+"):"),min, 1, max, 1, &ok); - if (!ok) { - statusMessage( "Remove node operation cancelled." ); + + else { + + + int doomedJim=-1, min=-1, max=-1; + bool ok=false; + + min = activeGraph.vertexFirstNumber(); + max = activeGraph.vertexLastNumber(); + qDebug("MW: min is %i and max is %i", min, max); + if (min==-1 || max==-1 ) { + qDebug("ERROR in finding min max nodeNumbers. Abort"); return; } + else if (nodeClicked && clickedNodeNumber >= 0 && clickedNodeNumber<= max ) { + doomedJim=clickedNodeNumber ; + } + else if (!nodeClicked ) { + doomedJim = QInputDialog::getInt(this,"Remove node",tr("Choose a node to remove between (" + + QString::number(min).toLatin1()+"..."+QString::number(max).toLatin1()+"):"),min, 1, max, 1, &ok); + if (!ok) { + statusMessage( "Remove node operation cancelled." ); + return; + } + } + qDebug ("MW: removing vertex with number %i from Graph", doomedJim); + activeGraph.vertexRemove(doomedJim); + qDebug("MW: removeNode() completed. Node %i removed completely.",doomedJim); + statusMessage( tr("Node removed completely. Ready. ") ); } - qDebug ("MW: removing vertex with number %i from Graph", doomedJim); - activeGraph.removeVertex(doomedJim); - clickedJimNumber=-1; + clickedNodeNumber=-1; nodeClicked=false; - graphChanged(); - qDebug("MW: removeNode() completed. Node %i removed completely.",doomedJim); - statusMessage( tr("Node removed completely. Ready. ") ); + slotNetworkChanged(); + + } -void MainWindow::slotChangeNodeProperties() { - qDebug() << "MW::slotChangeNodeProperties()"; +/** + * @brief MainWindow::slotEditNodePropertiesDialog + * Reads values from selected nodes + * then open Node Properties dialog + */ +void MainWindow::slotEditNodePropertiesDialog() { + + qDebug() << "MW::slotEditNodePropertiesDialog()"; // if (!fileLoaded && !networkModified ) { if (!activeGraph.vertices()) { QMessageBox::critical( @@ -4960,22 +6280,23 @@ void MainWindow::slotChangeNodeProperties() { statusMessage( tr("Nothing to remove.") ); return; } - int min=-1, max=-1, size = initNodeSize; - QColor color = QColor(initNodeColor); - QString shape= initNodeShape, label=""; + int min=-1, max=-1, size = appSettings["initNodeSize"].toInt(0, 10); + QColor color = QColor(appSettings["initNodeColor"]); + QString shape= appSettings["initNodeShape"]; + QString label=""; bool ok=false; if ( selectedNodes().count() == 0) { - min = activeGraph.firstVertexNumber(); - max = activeGraph.lastVertexNumber(); + min = activeGraph.vertexFirstNumber(); + max = activeGraph.vertexLastNumber(); qDebug("MW: min is %i and max is %i", min, max); if (min==-1 || max==-1 ) { qDebug("ERROR in finding min max nodeNumbers. Abort"); return; } - clickedJimNumber = QInputDialog::getInt( + clickedNodeNumber = QInputDialog::getInt( this, "Node Properties", tr("Choose a node between (" @@ -4989,29 +6310,29 @@ void MainWindow::slotChangeNodeProperties() { } else { foreach (QGraphicsItem *item, selectedNodes() ) { - if ( (clickedJim = qgraphicsitem_cast(item) )) { + if ( (clickedNode = qgraphicsitem_cast(item) )) { if ( selectedNodes().count() > 1 ) { - clickedJimNumber = clickedJim->nodeNumber(); - color = activeGraph.vertexColor( clickedJimNumber ); - shape = activeGraph.vertexShape( clickedJimNumber); - size = activeGraph.vertexSize ( clickedJimNumber); + clickedNodeNumber = clickedNode->nodeNumber(); + color = activeGraph.vertexColor( clickedNodeNumber ); + shape = activeGraph.vertexShape( clickedNodeNumber); + size = activeGraph.vertexSize ( clickedNodeNumber); } else { - clickedJimNumber = clickedJim->nodeNumber(); - label = activeGraph.vertexLabel( clickedJimNumber ); - color = activeGraph.vertexColor( clickedJimNumber ); - shape = activeGraph.vertexShape( clickedJimNumber); - size = activeGraph.vertexSize ( clickedJimNumber); + clickedNodeNumber = clickedNode->nodeNumber(); + label = activeGraph.vertexLabel( clickedNodeNumber ); + color = activeGraph.vertexColor( clickedNodeNumber ); + shape = activeGraph.vertexShape( clickedNodeNumber); + size = activeGraph.vertexSize ( clickedNodeNumber); } } } } - qDebug ()<< "MW: changing properties for "<< clickedJimNumber ; + qDebug ()<< "MW: changing properties for "<< clickedNodeNumber ; m_nodeEditDialog = new NodeEditDialog(this, label, size, color, shape) ; connect( m_nodeEditDialog, &NodeEditDialog::userChoices, - this, &MainWindow::slotNodeProperties ); + this, &MainWindow::slotEditNodeProperties ); m_nodeEditDialog->exec(); @@ -5019,106 +6340,620 @@ void MainWindow::slotChangeNodeProperties() { } - -void MainWindow::slotNodeProperties( const QString label, const int size, +/** + * @brief MainWindow::slotEditNodeProperties + * Applies new (user-defined) values to all selected nodes + * Called on exit from NodeEditDialog + * @param label + * @param size + * @param value + * @param color + * @param shape + */ +void MainWindow::slotEditNodeProperties( const QString label, const int size, const QString value, const QColor color, const QString shape) { - qDebug()<< "MW::slotNodeProperties() " + qDebug()<< "MW::slotEditNodeProperties() " << " label " << label << " size " << size << "value " << value << " color " << color << " shape " << shape - << " clickedJimNumber " <(item) )) { + if ( (clickedNode = qgraphicsitem_cast(item) )) { - clickedJimNumber = clickedJim->nodeNumber(); + clickedNodeNumber = clickedNode->nodeNumber(); if ( selectedNodes().count() > 1 ) { - activeGraph.setVertexLabel( - clickedJimNumber, - label + QString::number(clickedJimNumber) + activeGraph.vertexLabelSet( + clickedNodeNumber, + label + QString::number(clickedNodeNumber) ); } else - activeGraph.setVertexLabel( - clickedJimNumber, + activeGraph.vertexLabelSet( + clickedNodeNumber, label ); - if (!showLabels()) - displayNodeLabelsAct->setChecked(true); + if ( label !="" && appSettings["initNodeLabelsVisibility"] != "true") + slotOptionsNodeLabelsVisibility(true); - qDebug () << clickedJimNumber; + qDebug () << clickedNodeNumber; qDebug()<<"MW: updating color "; - activeGraph.setVertexColor( clickedJimNumber, color.name()); + activeGraph.vertexColorSet( clickedNodeNumber, color.name()); qDebug()<<"MW: updating size "; - activeGraph.setVertexSize(clickedJimNumber,size); + activeGraph.vertexSizeSet(clickedNodeNumber,size); qDebug()<<"MW: updating shape "; - activeGraph.setVertexShape( clickedJimNumber, shape); - clickedJim->setShape(shape); + activeGraph.vertexShapeSet( clickedNodeNumber, shape); + clickedNode->setShape(shape); } } - clickedJim=0; - clickedJimNumber=-1; + clickedNode=0; + clickedNodeNumber=-1; - graphChanged(); + slotNetworkChanged(); statusMessage( tr("Ready. ")); } + + + + + + + + +/** + * @brief MainWindow::slotEditNodeColorAll + * Changes the color of all nodes to parameter color + * Calls activeGraph.vertexColorAllSet to do the work + * If parameter color is invalid, opens a QColorDialog to + * select a new node color for all nodes. + * Called from Settings Dialog and Edit menu option + * @param color + */ +void MainWindow::slotEditNodeColorAll(QColor color){ + if (!color.isValid()) { + color = QColorDialog::getColor( QColor ( appSettings["initNodeColor"] ), + this, + "Change the color of all nodes" ); + } + if (color.isValid()) { + appSettings["initNodeColor"] = color.name(); + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + qDebug() << "MW::slotEditNodeColorAll() : " + << appSettings["initNodeColor"]; + activeGraph.vertexColorAllSet(appSettings["initNodeColor"]); + QApplication::restoreOverrideCursor(); + statusMessage( tr("Ready. ") ); + } + else { + // user pressed Cancel + statusMessage( tr("Invalid color. ") ); + } +} + + + + +/** + * @brief MainWindow::slotEditNodeSizeAll + * Changes the size of nodes to newSize. + * Calls activeGraph.vertexSizeAllSet to do the work. + * Called from Edit menu item, SettingsDialog + * If newSize = 0 asks the user a new size for all nodes + * If normalized = true, changes node sizes according to their plethos + * @param newSize + * @param normalized + */ +void MainWindow::slotEditNodeSizeAll(int newSize, const bool &normalized) { + qDebug () << "MW: slotEditNodeSizeAll() - " + << " newSize " << newSize ; + if ( newSize == 0 && !normalized ) { + bool ok=true; + newSize = QInputDialog::getInt( + this, + "Change node size", + tr("Select new size for all nodes: (1-16)"), + appSettings["initNodeSize"].toInt(0, 10), 1, 16, 1, &ok ); + + if (!ok) { + statusMessage( "Change node size operation cancelled." ); + return; + } + } + + if ( normalized ) { + int N = activeNodes() ; + if ( N < 100) { + newSize = 8; + } + else if ( N < 200) { + newSize = 7; + } + if ( N >= 200 && N < 500){ + newSize = 6; + } + else if ( N >= 500 && N < 1000) { + newSize = 6; + } + else if ( N >= 1000) { + newSize = 5; + } + } + appSettings["initNodeSize"]= QString::number(newSize); + nodeSizesByOutDegreeAct->setChecked(false); + toolBoxNodeSizesByOutDegreeBx->setChecked(false); + nodeSizesByInDegreeAct->setChecked(false); + toolBoxNodeSizesByInDegreeBx->setChecked(false); + + activeGraph.vertexSizeAllSet(newSize); + + slotNetworkChanged(); + statusBar()->showMessage (QString(tr("Ready")), statusBarDuration) ; + return; +} + + + + + + +/** + * @brief MainWindow::slotEditNodeShape + * If shape == null, prompts the user a list of available node shapes to select. + * Then changes the shape of all nodes/vertices accordingly. + * If vertex is non-zero, changes the shape of that node only. + * Called when user clicks on Edit -> Node > Change all nodes shapes + * Called from SettingsDialog when the user has selected a new default node shape + * Calls Graph::vertexShapeAllSet(QString) + * @param shape + * @param vertex + */ +void MainWindow::slotEditNodeShape(QString shape, const int vertex) { + qDebug() << "MW::slotEditNodeShape() - vertex " << vertex + << " (0 means all) - new shape " << shape; + + if (shape==QString::null) { + bool ok=false; + QStringList lst; + lst << "box"<< "circle"<< "diamond"<< "ellipse"<< "triangle" << "star"; + shape = QInputDialog::getItem(this, "Node shape", "Select a shape for all nodes: ", lst, 1, true, &ok); + if ( !ok ) { + //user pressed Cancel + statusBar()->showMessage (QString(tr("Change node shapes aborted...")), statusBarDuration) ; + return; + } + } + + if (vertex == 0) { //change all nodes shapes + slotNetworkChanged(); + activeGraph.vertexShapeAllSet(shape); + appSettings["initNodeShape"] = shape; + statusBar()->showMessage (QString(tr("All shapes have been changed. Ready")), statusBarDuration) ; + + } + else { //only one + activeGraph.vertexShapeSet( vertex, shape); + statusBar()->showMessage (QString(tr("Node shape has been changed. Ready")), statusBarDuration) ; + } +} + + + + +/** + * @brief MainWindow::slotEditNodeNumberSize + * Changes the size of one or all node numbers. + * Called from Edit menu option and SettingsDialog + * if newSize=0, asks the user to enter a new node number font size + * if v1=0, it changes all node numbers + * @param v1 + * @param newSize + */ +void MainWindow::slotEditNodeNumberSize(int v1, int newSize, const bool prompt) { + bool ok=false; + qDebug() << "MW::slotEditNodeNumberSize - newSize " << newSize; + if (prompt) { + newSize = QInputDialog::getInt(this, "Change text size", + tr("Change all node numbers size to: (1-16)"),appSettings["initNodeNumberSize"].toInt(0,10), 1, 16, 1, &ok ); + if (!ok) { + statusMessage( tr("Change font size: Aborted.") ); + return; + } + } + if (v1) { //change one node number only + activeGraph.vertexNumberSizeSet(v1, newSize); + } + else { //change all + appSettings["initNodeNumberSize"] = QString::number(newSize); + activeGraph.vertexNumberSizeSetAll(newSize); + } + statusMessage( tr("Changed node numbers size. Ready.") ); +} + + + + +/** + * @brief MainWindow::slotEditNodeNumbersColor + * Changes the color of all nodes' numbers. + * Called from Edit menu option and Settings dialog. + * Asks the user to enter a new node number color + */ +void MainWindow::slotEditNodeNumbersColor(QColor color){ + qDebug() << "MW:slotEditNodeNumbersColor() - new color " << color; + if (!color.isValid()) { + color = QColorDialog::getColor( QColor ( appSettings["initNodeNumberColor"] ), + this, + "Change the color of all node numbers" ); + } + + if (color.isValid()) { + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + QList list= scene->items(); + for (QList::iterator it=list.begin(); it!=list.end(); it++) { + if ( (*it)->type() == TypeNumber) { + NodeNumber *jimNumber = (NodeNumber *) (*it); + jimNumber->update(); + jimNumber->setDefaultTextColor(color); + } + } + appSettings["initNodeNumberColor"] = color.name(); + activeGraph.vertexNumberColorInit( color.name() ); + QApplication::restoreOverrideCursor(); + statusMessage( tr("Numbers' colors changed. Ready. ") ); + } + else { + // user pressed Cancel + statusMessage( tr("Invalid color. ") ); + } + +} + + +/** + * @brief MainWindow::slotEditNodeNumberDistance + * Changes the distance of one or all node numbers from their nodes. + * Called from Edit menu option and SettingsDialog + * if newDistance=0, asks the user to enter a new node number distance + * if v1=0, it changes all node number distances + * @param v1 + * @param newDistance + */ +void MainWindow::slotEditNodeNumberDistance(int v1, int newDistance) { + bool ok=false; + qDebug() << "MW::slotEditNodeNumberDistance - newSize " << newDistance; + if (!newDistance) { + newDistance = QInputDialog::getInt( + this, "Change node number distance", + tr("Change all node numbers distance from their nodes to: (1-16)"), + appSettings["initNodeNumberDistance"].toInt(0,10), 1, 16, 1, &ok ); + if (!ok) { + statusMessage( tr("Change node number distance aborted.") ); + return; + } + } + if (v1) { //change one node number distance only + activeGraph.vertexNumberDistanceSet(v1, newDistance); + } + else { //change all + appSettings["initNodeNumberDistance"] = QString::number(newDistance); + activeGraph.vertexNumberDistanceSetAll(newDistance); + } + statusMessage( tr("Changed node number distance. Ready.") ); +} + + + +/** + * @brief MainWindow::slotEditNodeLabelSize + * Changes the size of one or all node Labels. + * Called from Edit menu option and SettingsDialog + * if newSize=0, asks the user to enter a new node Label font size + * if v1=0, it changes all node Labels + * @param v1 + * @param newSize + */ +void MainWindow::slotEditNodeLabelSize(int v1, int newSize) { + bool ok=false; + qDebug() << "MW::slotEditNodeLabelSize - newSize " << newSize; + if (!newSize) { + newSize = QInputDialog::getInt(this, "Change text size", + tr("Change all node labels text size to: (1-16)"), + appSettings["initNodeLabelSize"].toInt(0,10), 1, 16, 1, &ok ); + if (!ok) { + statusMessage( tr("Change font size: Aborted.") ); + return; + } + } + if (v1) { //change one node Label only + activeGraph.vertexLabelSizeSet(v1, newSize); + } + else { //change all + appSettings["initNodeLabelSize"] = QString::number(newSize); + activeGraph.vertexLabelSizeAllSet(newSize); + } + statusMessage( tr("Changed node label size. Ready.") ); +} + + + + + + + +/** + * @brief MainWindow::slotEditNodeLabelsColor + * Changes the color of all nodes' labels. + * Asks the user to enter a new node label color + */ +void MainWindow::slotEditNodeLabelsColor(QColor color){ + qDebug() << "MW:slotEditNodeNumbersColor() - new color " << color; + if (!color.isValid()) { + color = QColorDialog::getColor( QColor ( appSettings["initNodeLabelColor"] ), + this, + "Change the color of all node labels" ); + } + if (color.isValid()) { + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + QList list= scene->items(); + for (QList::iterator it=list.begin(); it!=list.end(); it++) + if ( (*it)->type() == TypeNode ) { + Node *jim = (Node *) (*it); + jim->label()->update(); + jim->label()->setDefaultTextColor(color); + activeGraph.vertexLabelColorSet (jim->nodeNumber(), color.name()); + } + appSettings["initNodeLabelColor"] = color.name(); + activeGraph.vertexLabelColorInit(color.name()); + optionsNodeLabelsVisibilityAct->setChecked(true); + QApplication::restoreOverrideCursor(); + statusMessage( tr("Label colors changed. Ready. ") ); + } + else { + // user pressed Cancel + statusMessage( tr("Invalid color. ") ); + } +} + + + + +/** + * @brief MainWindow::slotEditNodeLabelDistance + * Changes the distance of one or all node label from their nodes. + * Called from Edit menu option and SettingsDialog + * if newDistance=0, asks the user to enter a new node label distance + * if v1=0, it changes all node label distances + * @param v1 + * @param newDistance + */ +void MainWindow::slotEditNodeLabelDistance(int v1, int newDistance) { + bool ok=false; + qDebug() << "MW::slotEditNodeLabelDistance - newSize " << newDistance; + if (!newDistance) { + newDistance = QInputDialog::getInt( + this, "Change node label distance", + tr("Change all node labels distance from their nodes to: (1-16)"), + appSettings["initNodeLabelDistance"].toInt(0,10), 1, 16, 1, &ok ); + if (!ok) { + statusMessage( tr("Change node label distance aborted.") ); + return; + } + } + if (v1) { //change one node label distance only + activeGraph.vertexLabelDistanceSet(v1, newDistance); + } + else { //change all + appSettings["initNodeLabelDistance"] = QString::number(newDistance); + activeGraph.vertexLabelDistanceAllSet(newDistance); + } + statusMessage( tr("Changed node label distance. Ready.") ); +} + + + +/** + * @brief MainWindow::slotEditNodeOpenContextMenu + * Called from GW when the user has right-clicked on a node + * Opens a node context menu with some options when the user right-clicks on a node + */ +void MainWindow::slotEditNodeOpenContextMenu() { + clickedNodeNumber=clickedNode->nodeNumber(); + qDebug("MW: slotEditNodeOpenContextMenu() for node %i at %i, %i", + clickedNodeNumber, QCursor::pos().x(), QCursor::pos().y()); + + QMenu *nodeContextMenu = new QMenu(QString::number(clickedNodeNumber), this); + Q_CHECK_PTR( nodeContextMenu ); //displays "out of memory" if needed + int nodeCount = selectedNodes().count(); + if ( nodeCount == 1) { + nodeContextMenu -> addAction( tr("## NODE ") + QString::number(clickedNodeNumber) + " ## "); + } + else { + nodeContextMenu -> addAction( + tr("## NODE ") + QString::number(clickedNodeNumber) + + " ## " + tr(" (selected nodes: ") + + QString::number (selectedNodes().count() ) + ")"); + } + + nodeContextMenu -> addSeparator(); + + nodeContextMenu -> addAction(editNodePropertiesAct ); + + nodeContextMenu -> addSeparator(); + + nodeContextMenu -> addAction(editEdgeAddAct); + + nodeContextMenu -> addSeparator(); + + nodeContextMenu -> addAction(editNodeRemoveAct ); + + if (nodeCount > 1 ){ + editNodeRemoveAct->setText(tr("Remove ") + + QString::number(nodeCount) + + tr(" nodes")); + } + else { + editNodeRemoveAct->setText(tr("Remove ") + + QString::number(nodeCount) + + tr(" node")); + } + nodeContextMenu -> addSeparator(); + + + //QCursor::pos() is good only for menus not related with node coordinates + nodeContextMenu -> exec(QCursor::pos() ); + delete nodeContextMenu; + clickedNodeNumber=-1; //undo node selection +} + + + + + +/** +* When the user clicks on a node, displays some information about it on the status bar. +*/ +void MainWindow::nodeInfoStatusBar ( Node *jim) { + qDebug ("MW: NodeInfoStatusBar()"); + edgeClicked=false; + nodeClicked=true; + clickedNode=jim; + clickedNodeNumber=clickedNode->nodeNumber(); + int inDegree=activeGraph.vertexDegreeIn(clickedNodeNumber); + int outDegree=activeGraph.vertexDegreeOut(clickedNodeNumber); + selectedNodeLCD->display (clickedNodeNumber); + inDegreeLCD->display (inDegree); + outDegreeLCD->display (outDegree); + if (activeGraph.vertices() < 500) + clucofLCD->display(activeGraph.clusteringCoefficientLocal(clickedNodeNumber)); + + statusMessage( QString(tr("(%1, %2); Node %3, label %4 - " + "In-Degree: %5, Out-Degree: %6")).arg( ceil( clickedNode->x() ) ) + .arg( ceil( clickedNode->y() )).arg( clickedNodeNumber ).arg( clickedNode->labelText() ) + .arg(inDegree).arg(outDegree) ); +} + + + + +/** + * @brief MainWindow::edgeInfoStatusBar + * Displays information on the status bar about and edge clicked by the user + * Called by GW::selectedEdge signal + * @param edge + */ +void MainWindow::edgeInfoStatusBar (Edge* edge) { + clickedEdge=edge; + edgeClicked=true; + nodeClicked=false; + + if (edge->isUndirected()) { + statusMessage( QString + (tr("Symmetric edge %1 <--> %2 of weight %3 has been selected. " + "Click again to unselect it.")) + .arg( edge->sourceNodeNumber() ).arg(edge->targetNodeNumber()) + .arg( edge->weight()) ) ; + + } + else { + statusMessage( QString(tr("Arc %1 --> %2 of weight %3 has been selected. " + "Click again to unselect it.")) + .arg( edge->sourceNodeNumber() ).arg(edge->targetNodeNumber()) + .arg(edge->weight()) ) ; + } +} + + + + +/** + Popups a context menu with some options when the user right-clicks on an Edge +*/ +void MainWindow::openEdgeContextMenu() { + int source=clickedEdge->sourceNodeNumber(); + int target=clickedEdge->targetNodeNumber(); + qDebug("MW: openEdgeContextMenu() for edge %i-%i at %i, %i",source, target, QCursor::pos().x(), QCursor::pos().y()); + QString edgeName=QString::number(source)+QString("->")+QString::number(target); + //make the menu + QMenu *edgeContextMenu = new QMenu(edgeName, this); + edgeContextMenu -> addAction( "## EDGE " + edgeName + " ## "); + edgeContextMenu -> addSeparator(); + edgeContextMenu -> addAction( editEdgeRemoveAct ); + edgeContextMenu -> addAction( editEdgeWeightAct ); + edgeContextMenu -> addAction( editEdgeLabelAct ); + edgeContextMenu -> addAction( editEdgeColorAct ); + edgeContextMenu -> exec(QCursor::pos() ); + delete edgeContextMenu; +} + + /** -* Adds a new edge between two nodes specified by the user. - Called when user clicks on the MW button "Add edge". -*/ -void MainWindow::slotAddEdge(){ - qDebug ("MW: slotAddEdge()"); + * @brief MainWindow::slotEditEdgeAdd + * Adds a new edge between two nodes specified by the user. + * Called when user clicks on the MW button/menu item "Add edge" + */ +void MainWindow::slotEditEdgeAdd(){ + qDebug ("MW: slotEditEdgeAdd()"); if (!fileLoaded && !networkModified ) { QMessageBox::critical(this, "Error",tr("No nodes!! \nCreate some nodes first."), "OK",0); statusMessage( tr("There are no nodes yet...") ); return; } - int sourceNode=-1, targetNode=-1, sourceIndex=-1, targetIndex=-1; + int sourceNode=-1, targetNode=-1; float weight=1; //weight of this new edge should be one... bool ok=false; - int min=activeGraph.firstVertexNumber(); - int max=activeGraph.lastVertexNumber(); + int min=activeGraph.vertexFirstNumber(); + int max=activeGraph.vertexLastNumber(); if (min==max) return; //if there is only one node -> no edge - if (!nodeClicked) { - sourceNode=QInputDialog::getInt(this, "Create new edge, Step 1",tr("This will draw a new edge between two nodes. \nEnter source node ("+QString::number(min).toLatin1()+"..."+QString::number(max).toLatin1()+"):"), min, 1, max , 1, &ok ) ; + if ( !nodeClicked || clickedNodeNumber == -1 ) { + sourceNode=QInputDialog::getInt( + this, + "Create new edge, Step 1", + tr("This will draw a new edge between two nodes. \n" + "Enter source node (" + +QString::number(min).toLatin1()+"..." + +QString::number(max).toLatin1()+"):"), min, 1, max , 1, &ok ) ; if (!ok) { statusMessage( "Add edge operation cancelled." ); return; } } - else sourceNode=clickedJimNumber; - qDebug () << "sourceNode=clickedJimNumber " << clickedJimNumber; - if ( (sourceIndex =activeGraph.hasVertex(sourceNode)) ==-1 ) { + else + sourceNode=clickedNodeNumber; + + qDebug () << "sourceNode=clickedNodeNumber " << clickedNodeNumber; + if ( activeGraph.vertexExists(sourceNode) ==-1 ) { statusMessage( tr("Aborting. ") ); QMessageBox::critical(this,"Error","No such node.", "OK",0); - qDebug ("MW: slotAddEdge: Cant find sourceNode %i.", sourceNode); + qDebug ("MW: slotEditEdgeAdd: Cant find sourceNode %i.", sourceNode); return; } targetNode=QInputDialog::getInt (this, "Create new edge, Step 2", - tr("Source node accepted. \nNow enter target node ("+ - QString::number(min).toLatin1()+"..."+QString::number(max) - .toLatin1()+"):"),min, min, max , 1, &ok) ; + tr( "Source node:" ) + QString::number( sourceNode ) + + tr(" \nNow enter a target node [") + + QString::number(min).toLatin1() + + "..." + + QString::number(max).toLatin1()+"]:",min, min, max , 1, &ok) ; if (!ok) { statusMessage( "Add edge target operation cancelled." ); return; } - if ( (targetIndex=activeGraph.hasVertex(targetNode)) ==-1 ) { + if ( activeGraph.vertexExists(targetNode) ==-1 ) { statusMessage( tr("Aborting. ") ); QMessageBox::critical(this,"Error","No such node.", "OK",0); - qDebug ("MW: slotAddEdge: Cant find targetNode %i",targetNode); + qDebug ("MW: slotEditEdgeAdd: Cant find targetNode %i",targetNode); return; } @@ -5131,44 +6966,54 @@ void MainWindow::slotAddEdge(){ return; } //Check if this edge already exists... - if (activeGraph.hasArc(sourceNode, targetNode)!=0 ) { + if (activeGraph.edgeExists(sourceNode, targetNode)!=0 ) { qDebug("edge exists. Aborting"); statusMessage( tr("Aborting. ") ); QMessageBox::critical(this,"Error","edge already exists.", "OK",0); return; } - addEdge(sourceNode, targetNode, weight); - graphChanged(); + slotEditEdgeCreate(sourceNode, targetNode, weight); + slotNetworkChanged(); statusMessage( tr("Ready. ") ); } -/** - helper to slotAddEdge() above - Also called from GW::userMiddleClicked() signal when user creates edges with middle-clicks - Calls Graph::createEdge method to add the new edge to the active Graph -*/ -void MainWindow::addEdge (int v1, int v2, float weight) { - qDebug("MW: addEdge() - setting user preferences and calling Graph::createEdge(...)"); - bool drawArrows=displayEdgesArrowsAct->isChecked(); - int reciprocal=0; +/** + * @brief MainWindow::slotEditEdgeCreate + * helper to slotEditEdgeAdd() above + * Also called from GW::userMiddleClicked() signal when user creates edges with middle-clicks + * Calls Graph::edgeCreate method to add the new edge to the active Graph + * @param source + * @param target + * @param weight + */ +void MainWindow::slotEditEdgeCreate (const int &source, const int &target, const float &weight) { + qDebug()<< "MW: slotEditEdgeCreate() - setting user settings and calling Graph::edgeCreate(...)"; + //int reciprocal=0; bool bezier = false; - activeGraph.createEdge(v1, v2, weight, reciprocal, drawArrows, bezier); + activeGraph.edgeCreate( + source, target, weight, + appSettings["initEdgeColor"] , + ( editEdgeUndirectedAllAct->isChecked() ) ? 2:0, + ( editEdgeUndirectedAllAct->isChecked() ) ? false : + ( (appSettings["initEdgeArrows"] == "true") ? true: false) + , bezier); - if ( activeEdges() == 1 && changeRelationCombo->count() == 0 ) { - addRelation(); + if ( activeEdges() == 1 && editRelationChangeCombo->count() == 0 ) { + slotEditRelationAdd(); } } + /** -* Erases the clicked edge. Otherwise asks the user to specify one edge. -* First deletes arc reference from object nodeVector -* then deletes arc item from scene -**/ -void MainWindow::slotRemoveEdge(){ + * @brief MainWindow::slotEditEdgeRemove + * Erases the clicked edge. Otherwise asks the user to specify one edge. + * First deletes arc reference from object nodeVector then deletes arc item from scene + */ +void MainWindow::slotEditEdgeRemove(){ if ( (!fileLoaded && !networkModified) || activeEdges() ==0 ) { QMessageBox::critical(this, "Error",tr("There are no edges! \nLoad a network file or create a new network first."), "OK",0); statusMessage( tr("No edges to remove - sorry.") ); @@ -5177,8 +7022,8 @@ void MainWindow::slotRemoveEdge(){ int min=0, max=0, sourceNode=-1, targetNode=-1; bool ok=false; - min=activeGraph.firstVertexNumber(); - max=activeGraph.lastVertexNumber(); + min=activeGraph.vertexFirstNumber(); + max=activeGraph.vertexLastNumber(); if (!edgeClicked) { sourceNode=QInputDialog::getInt( @@ -5190,19 +7035,22 @@ void MainWindow::slotRemoveEdge(){ return; } - targetNode=QInputDialog::getInt(this, tr("Remove edge"), tr("Target node: (")+QString::number(min)+"..."+QString::number(max)+"):",min, 1, max , 1, &ok ) ; + targetNode=QInputDialog::getInt( + this, + tr("Remove edge"), + tr("Target node: (")+QString::number(min)+"..."+ + QString::number(max)+"):",min, 1, max , 1, &ok ) ; if (!ok) { statusMessage( "Remove edge operation cancelled." ); return; } - if ( activeGraph.hasArc(sourceNode, targetNode)!=0 ) { - if (activeGraph.symmetricEdge(sourceNode, targetNode) ) - graphicsWidget->unmakeEdgeReciprocal(targetNode, sourceNode); - graphicsWidget->eraseEdge(sourceNode, targetNode); - activeGraph.removeEdge(sourceNode, targetNode); + if ( activeGraph.edgeExists(sourceNode, targetNode)!=0 ) { + activeGraph.edgeRemove(sourceNode, targetNode); } else { - QMessageBox::critical(this, "Remove edge",tr("There is no such edge."), "OK",0); + QMessageBox::critical( + this, + "Remove edge",tr("There is no such edge."), "OK",0); statusMessage( tr("There are no nodes yet...") ); return; } @@ -5211,75 +7059,91 @@ void MainWindow::slotRemoveEdge(){ else { sourceNode = clickedEdge->sourceNodeNumber(); targetNode = clickedEdge->targetNodeNumber(); - if (activeGraph.symmetricEdge(sourceNode, targetNode) ) { - QString s=QString::number(sourceNode); - QString t=QString::number(targetNode); - switch (QMessageBox::information( this, tr("Remove edge"), - tr("This edge is directed. \n") + - tr("Select what Direction to delete or Both..."), - s+" -> "+ t, t+" -> "+s, tr("Both"), 0, 1 )) + activeGraph.edgeRemove(sourceNode, targetNode); + + } + slotNetworkChanged(); + qDebug("MW: View items now: %i ", graphicsWidget->items().size()); + qDebug("MW: Scene items now: %i ", scene->items().size()); +} + + - { - case 0: - graphicsWidget->removeItem(clickedEdge); - activeGraph.removeEdge(sourceNode, targetNode); - //make new edge - // graphicsWidget->unmakeEdgeReciprocal(clickedEdge->targetNodeNumber(), clickedEdge->sourceNodeNumber()); - //FIXME weight should be the same - graphicsWidget->drawEdge(targetNode, sourceNode, 1, false, displayEdgesArrowsAct->isChecked(), initEdgeColor, false); - - break; - case 1: - clickedEdge->unmakeReciprocal(); - //graphicsWidget->removeItem(clickedEdge); - activeGraph.removeEdge(targetNode, sourceNode); - // graphicsWidget->drawEdge(i, j, false, drawArrowsAct->isChecked(), initEdgeColor, false); - break; - case 2: - graphicsWidget->removeItem(clickedEdge); - activeGraph.removeEdge(sourceNode, targetNode); - activeGraph.removeEdge(targetNode, sourceNode); - } - } - else { - graphicsWidget->removeItem(clickedEdge); - activeGraph.removeEdge(sourceNode, targetNode); - } + +/** + * @brief MainWindow::slotEditEdgeLabel + */ +void MainWindow::slotEditEdgeLabel(){ + qDebug() << "MW::slotEditEdgeLabel()"; + if ( ( !fileLoaded && !networkModified) || activeEdges() ==0 ) { + QMessageBox::critical(this, "Error", + tr("There are no edges! \n" + "Load a network file or create a new network first."), "OK",0); + statusMessage( tr("No edges present...") ); + return; } - graphChanged(); - qDebug("MW: View items now: %i ", graphicsWidget->items().size()); - qDebug("MW: Scene items now: %i ", scene->items().size()); -} + int sourceNode=-1, targetNode=-1; + bool ok=false; + int min=activeGraph.vertexFirstNumber(); + int max=activeGraph.vertexLastNumber(); + if (!edgeClicked) + { //no edge clicked. Ask user to define an edge. + sourceNode=QInputDialog::getInt(this, + "Change edge label", + tr("Select edge source node: ("+ + QString::number(min).toLatin1()+ + "..."+QString::number(max).toLatin1()+ + "):"), min, 1, max , 1, &ok) ; + if (!ok) { + statusMessage( "Change edge label operation cancelled." ); + return; + } + targetNode=QInputDialog::getInt(this, + "Change edge label...", + tr("Select edge target node: ("+ + QString::number(min).toLatin1()+"..." + + QString::number(max).toLatin1()+"):"), + min, 1, max , 1, &ok ) ; + if (!ok) { + statusMessage( "Change edge label operation cancelled." ); + return; + } + if ( ! activeGraph.edgeExists (sourceNode, targetNode ) ) { + statusMessage( tr("There is no such edge. ") ); + QMessageBox::critical(this, "Error", + tr("No edge! \nNo such edge found in current network."), "OK",0); + return; + } + } + else + { //edge has been clicked. + sourceNode = clickedEdge->sourceNodeNumber(); + targetNode = clickedEdge->targetNodeNumber(); + } + QString label = QInputDialog::getText( this, tr("Change edge label"), + tr("Enter label: ") ); -/** -* Changes the color of all nodes -*/ -void MainWindow::slotAllNodesColor(){ - QColor color = QColorDialog::getColor( Qt::red, this, - "Change the color of all nodes" ); - if (color.isValid()) { - initNodeColor=color.name(); - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - qDebug() << "MainWindow::slotAllNodesColor() : " << initNodeColor; - activeGraph.setAllVerticesColor(initNodeColor); - QApplication::restoreOverrideCursor(); + if ( !label.isEmpty()) { + qDebug() << "MW::slotEditEdgeLabel() - " << sourceNode << " -> " + << targetNode << " new label " << label; + activeGraph.edgeLabelSet( sourceNode, targetNode, label); + slotOptionsEdgeLabelsVisibility(true); statusMessage( tr("Ready. ") ); } else { - // user pressed Cancel - statusMessage( tr("Nodes color change aborted. ") ); + statusMessage( tr("Change edge label aborted. ") ); } } @@ -5288,20 +7152,56 @@ void MainWindow::slotAllNodesColor(){ - -//TODO slotChangeEdgeLabel -void MainWindow::slotChangeEdgeLabel(){ - graphChanged(); +/** + * @brief MainWindow::slotEditEdgeColorAll + * It changes the color of all edges weighted below threshold to parameter color + * If color is not valid, it opens a QColorDialog + * If threshold == RAND_MAX it changes the color of all edges. + * Called from Edit -> Edges menu option and Settings Dialog. + * @param color = QColor() + * @param threshold = RAND_MAX + */ +void MainWindow::slotEditEdgeColorAll(QColor color,const int &threshold){ + if (!color.isValid()) { + QString text; + if (threshold < RAND_MAX) { + text = "Change the color of edges weighted < " + + QString::number(threshold) ; + } + else + text = "Change the color of all edges" ; + color = QColorDialog::getColor( Qt::red, this, + text); + } + if (color.isValid()) { + if (threshold < 0 ) { + appSettings["initEdgeColorNegative"]=color.name(); + } + else + appSettings["initEdgeColor"]=color.name(); + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + qDebug() << "MainWindow::slotEditEdgeColorAll() - new edge color: " << color.name(); + activeGraph.edgeColorAllSet(color.name(), threshold ); + QApplication::restoreOverrideCursor(); + slotNetworkChanged(); + statusMessage( tr("Ready. ") ); + } + else { + // user pressed Cancel + statusMessage( tr("edges color change aborted. ") ); + } } + /** -* Changes the colour of the clicked edge. -* If no edge is clicked, then it asks the user to specify one. -*/ -void MainWindow::slotChangeEdgeColor(){ - qDebug() << "MW::slotChangeEdgeColor()"; + * @brief MainWindow::slotEditEdgeColor + * Changes the color of the clicked edge. + * If no edge is clicked, then it asks the user to specify one. + */ +void MainWindow::slotEditEdgeColor(){ + qDebug() << "MW::slotEditEdgeColor()"; if ( ( !fileLoaded && !networkModified) || activeEdges() ==0 ) { QMessageBox::critical(this, "Error", tr("There are no edges! \nLoad a network file or create a new network first."), "OK",0); @@ -5312,8 +7212,8 @@ void MainWindow::slotChangeEdgeColor(){ int sourceNode=-1, targetNode=-1; bool ok=false; - int min=activeGraph.firstVertexNumber(); - int max=activeGraph.lastVertexNumber(); + int min=activeGraph.vertexFirstNumber(); + int max=activeGraph.vertexLastNumber(); if (!edgeClicked) { //no edge clicked. Ask user to define an edge. @@ -5338,7 +7238,7 @@ void MainWindow::slotChangeEdgeColor(){ return; } - if ( ! activeGraph.hasArc (sourceNode, targetNode ) ) { + if ( ! activeGraph.edgeExists(sourceNode, targetNode ) ) { statusMessage( tr("There is no such edge. ") ); QMessageBox::critical(this, "Error", tr("No edge! \nNo such edge found in current network."), "OK",0); @@ -5358,10 +7258,10 @@ void MainWindow::slotChangeEdgeColor(){ if ( color.isValid()) { QString newColor=color.name(); - qDebug() << "MW::slotChangeEdgeColor() - " << sourceNode << " -> " + qDebug() << "MW::slotEditEdgeColor() - " << sourceNode << " -> " << targetNode << " newColor " << newColor; - activeGraph.setEdgeColor( sourceNode, targetNode, newColor); + activeGraph.edgeColorSet( sourceNode, targetNode, newColor); statusMessage( tr("Ready. ") ); } else { @@ -5374,150 +7274,155 @@ void MainWindow::slotChangeEdgeColor(){ /** -* Changes the weight of the clicked edge. -* If no edge is clicked, asks the user to specify an Edge. -*/ -void MainWindow::slotChangeEdgeWeight(){ + * @brief MainWindow::slotEditEdgeWeight + * Changes the weight of the clicked edge. + * If no edge is clicked, asks the user to specify an Edge. + */ +void MainWindow::slotEditEdgeWeight(){ if ( ( !fileLoaded && !networkModified) || activeEdges() ==0 ) { - QMessageBox::critical(this, "Error",tr("There are no edges! \nLoad a network file or create a new network first."), "OK",0); + QMessageBox::critical( + this, "Error", + tr("There are no edges! \n" + "Load a network file or create a new network first."), "OK",0); statusMessage( tr("No edges present...") ); return; } - qDebug("MW::slotChangeEdgeWeight()"); + qDebug("MW::slotEditEdgeWeight()"); int sourceNode=-1, targetNode=-1; float newWeight=1.0; - int min=activeGraph.firstVertexNumber(); - int max=activeGraph.lastVertexNumber(); + int min=activeGraph.vertexFirstNumber(); + int max=activeGraph.vertexLastNumber(); bool ok=false; if (!edgeClicked) { - sourceNode=QInputDialog::getInt(this, "Change edge weight",tr("Select edge source node: ("+QString::number(min).toLatin1()+"..."+QString::number(max).toLatin1()+"):"), min, 1, max , 1, &ok) ; + sourceNode=QInputDialog::getInt( + this, + "Change edge weight", + tr("Select edge source node: ("+ + QString::number(min).toLatin1()+"..."+ + QString::number(max).toLatin1()+"):"), + min, 1, max , 1, &ok) ; if (!ok) { statusMessage( "Change edge weight operation cancelled." ); return; } - targetNode=QInputDialog::getInt(this, "Change edge weight...", tr("Select edge target node: ("+QString::number(min).toLatin1()+"..."+QString::number(max).toLatin1()+"):"),min, 1, max , 1, &ok ) ; + targetNode=QInputDialog::getInt( + this, + "Change edge weight...", + tr("Select edge target node: ("+ + QString::number(min).toLatin1()+"..."+ + QString::number(max).toLatin1()+"):"), + min, 1, max , 1, &ok ) ; if (!ok) { statusMessage( "Change edge weight operation cancelled." ); return; } qDebug("source %i target %i",sourceNode, targetNode); - - QList list=scene->items(); - for (QList::iterator it=list.begin(); it!= list.end() ; it++) - if ( (*it)->type()==TypeEdge) { - Edge *edge=(Edge*) (*it); - qDebug ("MW: searching edge..."); - if ( edge->sourceNodeNumber()==sourceNode && edge->targetNodeNumber()==targetNode ) { - qDebug("MW: edge found"); - newWeight=(float) QInputDialog::getDouble(this, - "Change edge weight...",tr("New edge Weight: "), 1, -100, 100 ,1, &ok ) ; - if (ok) { - edge->setWeight(newWeight); - edge->update(); - activeGraph.setArcWeight(sourceNode, targetNode, newWeight); - statusMessage( QString(tr("Ready.")) ); - return; - } - else { - statusMessage( QString(tr("input error. Abort.")) ); - return; - } - } - } } else { //edgeClicked - qDebug() << "MW: slotChangeedgeWeight() - an Edge has already been clicked"; + qDebug() << "MW: slotEditEdgeWeight() - an Edge has already been clicked"; sourceNode=clickedEdge->sourceNodeNumber(); targetNode=clickedEdge->targetNodeNumber(); - qDebug() << "MW: slotChangeEdgeWeight() from " + qDebug() << "MW: slotEditEdgeWeight() from " << sourceNode << " to " << targetNode; - if ( activeGraph.symmetricEdge(sourceNode, targetNode) ) { - QString s=QString::number(sourceNode); - QString t=QString::number(targetNode); - switch (QMessageBox::information( this, tr("Change edge weight"), - tr("This edge is reciprocal. \n") + - tr("Select what Direction to change or Both..."), - s+" -> "+ t, t+" -> "+s, tr("Both"), 0, 1 )) - { - case 0: - qDebug("MW: slotChangeEdgeWeight() real edge %i -> %i", sourceNode, targetNode); - newWeight=QInputDialog::getDouble(this, - "Change edge weight...",tr("New edge weight: "), 1.0, -100.0, 100.00 ,1, &ok) ; - if (ok) { - clickedEdge->setWeight(newWeight); - clickedEdge->update(); - qDebug()<<"MW: newWeight will be "<< newWeight; - activeGraph.setArcWeight(sourceNode, targetNode, newWeight); - statusMessage( QString(tr("Ready.")) ); - return; - } - else { - statusMessage( QString(tr("Change edge weight cancelled.")) ); - return; - } - break; - case 1: - qDebug("MW: slotChangeEdgeWeight() virtual edge %i -> %i",targetNode , sourceNode); - newWeight=(float) QInputDialog::getDouble(this, - "Change edge weight...",tr("New edge Weight: "), 1, -100, 100 ,1, &ok ) ; - if (ok) { - qDebug()<<"MW: newWeight will be "<< newWeight; - activeGraph.setArcWeight( targetNode, sourceNode, newWeight); - statusMessage( QString(tr("Ready.")) ); - return; - } - else { - statusMessage( QString(tr("Change edge weight cancelled.")) ); - return; - } - break; - case 2: - qDebug("MW: slotChangeEdgeWeight() both directions %i <-> %i",targetNode , sourceNode); - newWeight=(float) QInputDialog::getDouble(this, - "Change edge weight...",tr("New edge Weight: "), 1, -100, 100 ,1, &ok ) ; - - if (ok) { - qDebug()<<"MW: Changing first direction. NewWeight will be "<< newWeight; - activeGraph.setArcWeight(sourceNode, targetNode, newWeight); - qDebug()<<"MW: Changing opposite direction. NewWeight will be "<< newWeight; - activeGraph.setArcWeight( targetNode, sourceNode, newWeight); - statusMessage( QString(tr("Ready.")) ); - return; - } - else { - statusMessage( QString(tr("Change edge weight cancelled.")) ); - return; - } - break; - } + + } + + float oldWeight= 0; + if ( ( oldWeight= activeGraph.edgeWeight(sourceNode, targetNode)) != 0 ) { + newWeight=(float) QInputDialog::getDouble( + this, + "Change edge weight...", + tr("New edge Weight: "), + oldWeight, -100, 100 ,1, &ok ) ; + + if (ok) { + activeGraph.edgeWeightSet(sourceNode, targetNode, newWeight, + activeGraph.isUndirected() + ); } else { - qDebug() << "MW: slotChangeEdgeWeight() real edge " << sourceNode - << " -> " <setWeight(newWeight); - qDebug() << "MW: slotChangeEdgeWeight() calling update "; - clickedEdge->update(); - qDebug()<<"MW: newWeight will be "<< newWeight; - activeGraph.setArcWeight(sourceNode, targetNode, newWeight); - statusMessage( QString(tr("Ready.")) ); - return; - } - else { - statusMessage( QString(tr("Change edge weight cancelled.")) ); - return; - } + statusMessage( QString(tr("Change edge weight cancelled.")) ); + return; + } + } + + //edgeClicked=false; +} + + + +/** + * @brief MainWindow::slotEditEdgeSymmetrizeAll + * Symmetrize the ties between every two connected nodes. + * If there is an arc from Node A to Node B, + * then a new arc from Node B to Node is created of the same weight. + * Thus, all arcs become reciprocal and the network becomes symmetric + * with a symmetric adjacency matrix + */ +void MainWindow::slotEditEdgeSymmetrizeAll(){ + if ( ( !fileLoaded && !networkModified) || activeEdges() ==0 ) { + QMessageBox::critical(this, "Error",tr("There are no edges! \nLoad a network file or create a new network first."), "OK",0); + statusMessage( tr("No edges present...") ); + return; + } + qDebug("MW: slotEditEdgeSymmetrizeAll() calling symmetrize"); + activeGraph.symmetrize(); + QMessageBox::information(this, + "Symmetrize", + tr("All arcs are reciprocal. \n" + "The network is symmetric."), "OK",0); + statusBar()->showMessage (QString(tr("Ready")), statusBarDuration) ; +} + + +/** + * @brief MainWindow::slotEditEdgeUndirectedAll + * Tranforms all directed arcs to undirected edges. + * The result is a undirected and symmetric network + */ +void MainWindow::slotEditEdgeUndirectedAll(const bool &toggle){ + + if (toggle) { + qDebug("MW: slotEditEdgeUndirectedAll() calling Graph::undirectedSet()"); + activeGraph.undirectedSet(toggle); + optionsEdgeArrowsAct->setChecked(false); + if (activeEdges() !=0 ) { + statusBar()->showMessage ( + QString( + tr("Undirected data mode. " + "All existing directed edges transformed to " + "undirected. Ready")), statusBarDuration) ; + + } + else { + statusBar()->showMessage ( + QString( + tr("Undirected data mode. " + "Any edge you add will be undirected. Ready")), statusBarDuration) ; + } + } + else { + activeGraph.undirectedSet(toggle); + optionsEdgeArrowsAct->trigger(); + optionsEdgeArrowsAct->setChecked(true); + if (activeEdges() !=0 ) { + statusBar()->showMessage ( + QString( + tr("Directed data mode. " + "All existing undirected edges transformed to " + "directed. Ready")), statusBarDuration) ; } - edgeClicked=false; + else { + statusBar()->showMessage ( + QString( + tr("Directed data mode. " + "Any edge you add will be directed. Ready")), statusBarDuration) ; + } } } @@ -5525,6 +7430,7 @@ void MainWindow::slotChangeEdgeWeight(){ + /** * Filters Nodes by their value TODO slotFilterNodes @@ -5542,7 +7448,7 @@ void MainWindow::slotFilterNodes(){ /** * @brief MainWindow::slotFilterIsolateNodes - *Calls Graph::filterIsolateVertices to toggle visibility of isolated vertices + *Calls Graph::vertexIsolateFilter to toggle visibility of isolated vertices */ void MainWindow::slotFilterIsolateNodes(bool checked){ Q_UNUSED(checked); @@ -5552,7 +7458,7 @@ void MainWindow::slotFilterIsolateNodes(bool checked){ return; } qDebug()<< "MW: slotFilterIsolateNodes"; - activeGraph.filterIsolateVertices( ! filterIsolateNodesAct->isChecked() ); + activeGraph.vertexIsolateFilter( ! filterIsolateNodesAct->isChecked() ); statusMessage( QString(tr("Isolate nodes visibility toggled!")) ); } @@ -5567,7 +7473,7 @@ void MainWindow::slotShowFilterEdgesDialog() { statusMessage( QString(tr("Load a network file first. \nThen you may ask me to compute something!")) ); return; } - m_filterEdgesByWeightDialog.exec() ; + m_DialogEdgeFilterByWeight.exec() ; } @@ -5582,7 +7488,7 @@ void MainWindow::slotShowFilterEdgesDialog() { TODO slotTransformNodes2Edges */ void MainWindow::slotTransformNodes2Edges(){ - graphChanged(); + slotNetworkChanged(); } @@ -5590,20 +7496,7 @@ void MainWindow::slotTransformNodes2Edges(){ -/** -* Converts all edges to double edges, so that the network becomes undirected (symmetric adjacency matrix). -*/ -void MainWindow::slotSymmetrize(){ - if ( ( !fileLoaded && !networkModified) || activeEdges() ==0 ) { - QMessageBox::critical(this, "Error",tr("There are no edges! \nLoad a network file or create a new network first."), "OK",0); - statusMessage( tr("No edges present...") ); - return; - } - qDebug("MW: slotSymmetrize() calling symmetrize"); - activeGraph.symmetrize(); - QMessageBox::information(this, "Symmetrize",tr("All edges are reciprocal. \nYour network is symmetric..."), "OK",0); - statusBar()->showMessage (QString(tr("Ready")), statusBarDuration) ; -} + @@ -5630,20 +7523,24 @@ void MainWindow::slotLayoutRandom(){ if (!fileLoaded && !networkModified ) { QMessageBox::critical( this, "Error", - tr("Sorry, I can't follow! " + tr("Sorry, nothing to do! " "\nLoad a network file or create a new network first. \n" "Then we can talk about layouts!"), "OK",0); statusMessage( QString(tr("Nothing to layout! Are you dreaming?")) ); return; } - double maxWidth=graphicsWidget->width(); - double maxHeight=graphicsWidget->height(); - statusMessage( QString(tr("Randomizing nodes positions. Please wait...")) ); + graphicsWidget->clearGuides(); - createProgressBar(); - activeGraph.layoutRandom(maxWidth, maxHeight); + statusMessage( tr("Embedding Random Layout. Please wait...") ); + progressMsg = tr("Embedding Random Layout. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + createProgressBar(0,progressMsg); + + activeGraph.layoutRandom(); + destroyProgressBar(); - statusMessage( tr("Node positions are now randomized.") ); + + statusMessage( tr("Nodes in random positions.") ); } @@ -5666,11 +7563,15 @@ void MainWindow::slotLayoutCircularRandom(){ double x0=scene->width()/2.0; double y0=scene->height()/2.0; double maxRadius=(graphicsWidget->height()/2.0)-50; //pixels - statusMessage( QString(tr("Calculating new nodes positions. Please wait...")) ); - graphicsWidget->clearGuides(); - createProgressBar(); + + slotLayoutGuides(false); + statusMessage( QString(tr("Embedding Random Circular model. Please wait...")) ); + progressMsg = "Embedding Random Circular model. \n" + "Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar(0,progressMsg ); activeGraph.layoutCircularRandom(x0, y0, maxRadius); destroyProgressBar(); + slotLayoutGuides(true); statusMessage( tr("Nodes in random circles.") ); } @@ -5679,35 +7580,28 @@ void MainWindow::slotLayoutCircularRandom(){ /** - slotLayoutSpringEmbedder called from menu or toolbox checkbox -*/ -void MainWindow::slotLayoutSpringEmbedder(bool state ){ + * @brief MainWindow::slotLayoutSpringEmbedder + * Calls Graph::layoutForceDirectedSpringEmbedder to embed a + * spring-gravitational model + * Called from menu or toolbox checkbox + */ +void MainWindow::slotLayoutSpringEmbedder(){ qDebug()<< "MW:slotLayoutSpringEmbedder"; if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are node nodes yet!\nLoad a network file or create a new network first. \nThen we can talk about layouts!"), "OK",0); + QMessageBox::critical(this, "Error",tr("There are node nodes yet!\n" + "Load a network file or create a new network first. \n" + "Then we can talk about layouts!"), "OK",0); statusMessage( tr("I am really sorry. You must really load a file first... ") ); - layoutEadesBx->setCheckState(Qt::Unchecked); return; } - //Stop any other layout running - layoutFruchtermanBx->setCheckState(Qt::Unchecked); - activeGraph.nodeMovement(!state, 2, graphicsWidget->width(), graphicsWidget->height()); - - scene->setItemIndexMethod (QGraphicsScene::NoIndex); //best when moving items - - if (state){ - statusMessage( tr("Embedding a spring-gravitational model on the network.... ") ); - layoutEadesBx->setCheckState(Qt::Checked); - activeGraph.nodeMovement(state, 1, graphicsWidget->width(), graphicsWidget->height()); - statusMessage( tr("Click on the checkbox \"Spring-Embedder\" to stop movement!") ); - } - else { - layoutEadesBx->setCheckState(Qt::Unchecked); - activeGraph.nodeMovement(state, 1, graphicsWidget->width(), graphicsWidget->height()); - statusMessage( tr("Movement stopped!") ); - } - scene->setItemIndexMethod (QGraphicsScene::BspTreeIndex); //best when not moving items + statusMessage( tr("Embedding Spring-Gravitational model (Eades).... ") ); + progressMsg = "Embedding Spring-Gravitational model (Eades). \n" + "Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar(0,progressMsg ); + activeGraph.layoutForceDirectedSpringEmbedder(100); + destroyProgressBar(); + statusMessage( tr("Spring-Gravitational (Eades) model embedded.") ); } @@ -5715,43 +7609,38 @@ void MainWindow::slotLayoutSpringEmbedder(bool state ){ /** - slotLayoutFruchterman called from menu -*/ + * @brief MainWindow::slotLayoutFruchterman + * Calls Graph::layoutForceDirectedFruchtermanReingold to embed + * a repelling-attracting forces model. + * Called from menu or toolbox + */ void MainWindow::slotLayoutFruchterman(){ + qDebug("MW: slotLayoutFruchterman ()"); if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are no nodes yet!\nLoad a network file or create a new network first. \nThen we can talk about layouts!"), "OK",0); + QMessageBox::critical(this, "Error",tr("There are no nodes yet!\n" + "Load a network file or create a new network first. \n" + "Then we can talk about layouts!"), "OK",0); statusMessage( tr("I am really sorry. You must really load a file first... ") ); return; } - if (layoutFruchtermanBx->checkState() == Qt::Unchecked){ - statusMessage( tr("Embedding a repelling-attracting forces model on the network.... ") ); - layoutFruchtermanBx->setCheckState(Qt::Checked); - statusMessage( tr("Click on the checkbox \"Fruchterman-Reingold\" to stop movement!") ); - } - else { - layoutFruchtermanBx->setCheckState(Qt::Unchecked); - statusMessage( tr("Movement stopped!") ); - } - -} + statusMessage( tr("Embedding a repelling-attracting forces model " + "(Fruchterman & Reingold) on the network.... ") ); + progressMsg = "Embedding a repelling-attracting forces model " + "(Fruchterman & Reingold) \n" + "Please wait (or disable progress bars from Options -> Settings)."; + createProgressBar(0,progressMsg ); + activeGraph.layoutForceDirectedFruchtermanReingold(100); -/** - Called when user presses button. - Calls Graph::startNodeMovement to embed a repelling-attracting forces layout... -*/ -void MainWindow::layoutFruchterman (int state){ - qDebug("MW: layoutFruchterman ()"); - layoutEadesBx->setChecked(false); - scene->setItemIndexMethod (QGraphicsScene::NoIndex); //best when moving items - activeGraph.nodeMovement(state, 2, graphicsWidget->width(), graphicsWidget->height()); - scene->setItemIndexMethod (QGraphicsScene::BspTreeIndex); //best when not moving items + destroyProgressBar(); + statusMessage( tr("Fruchterman & Reingold model embedded.") ); } + /** - * @brief MainWindow::slotLayoutNodeSizesByOutDegree + * @brief * Resizes all nodes according to their outDegree * Called when user selects the relevant menu entry or the option in the toolbox * @param checked @@ -5772,7 +7661,7 @@ void MainWindow::slotLayoutNodeSizesByOutDegree(bool checked){ if (checked != true) { qDebug("MW: slotLayoutNodeSizesByOutDegree() resetting size"); nodeSizesByOutDegreeAct->setChecked(false); - nodeSizesByOutDegreeBx->setChecked(false); + toolBoxNodeSizesByOutDegreeBx->setChecked(false); QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); @@ -5784,9 +7673,9 @@ void MainWindow::slotLayoutNodeSizesByOutDegree(bool checked){ } qDebug("MW: slotLayoutNodeSizesByOutDegree() setting size"); nodeSizesByOutDegreeAct->setChecked(true); - nodeSizesByOutDegreeBx->setChecked(true); + toolBoxNodeSizesByOutDegreeBx->setChecked(true); nodeSizesByInDegreeAct->setChecked(false); - nodeSizesByInDegreeBx->setChecked(false); + toolBoxNodeSizesByInDegreeBx->setChecked(false); askAboutWeights(); @@ -5803,14 +7692,17 @@ void MainWindow::slotLayoutNodeSizesByOutDegree(bool checked){ /** - * @brief MainWindow::slotLayoutNodeSizesByInDegree + * @brief * Resizes all nodes according to their inDegree * Called when user selects the relevant menu entry or the option in the toolbox * @param checked */ void MainWindow::slotLayoutNodeSizesByInDegree(bool checked){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("You must be dreaming! \nLoad a network file or create a new network first. \nThen we can talk about layouts!"), "OK",0); + QMessageBox::critical(this, + "Error", + tr("Load a network file or create a new network first. \n" + "Then we can talk about layouts!"), "OK",0); statusMessage( tr("I am really sorry. You must really load a file first... ") ); return; } @@ -5820,7 +7712,7 @@ void MainWindow::slotLayoutNodeSizesByInDegree(bool checked){ if (checked != true) { qDebug("MW: slotLayoutNodeSizesByInDegree() resetting size"); nodeSizesByInDegreeAct->setChecked(false); - nodeSizesByInDegreeBx->setChecked(false); + toolBoxNodeSizesByInDegreeBx->setChecked(false); QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); @@ -5832,9 +7724,9 @@ void MainWindow::slotLayoutNodeSizesByInDegree(bool checked){ } qDebug("MW: slotLayoutNodeSizesByInDegree() setting size"); nodeSizesByOutDegreeAct->setChecked(false); - nodeSizesByOutDegreeBx->setChecked(false); + toolBoxNodeSizesByOutDegreeBx->setChecked(false); nodeSizesByInDegreeAct->setChecked(true); - nodeSizesByInDegreeBx->setChecked(true); + toolBoxNodeSizesByInDegreeBx->setChecked(true); askAboutWeights(); @@ -5851,23 +7743,30 @@ void MainWindow::slotLayoutNodeSizesByInDegree(bool checked){ /** - * @brief MainWindow::slotLayoutGuides + * @brief + * Enables/disables layout guides + * Called from * @param state */ -void MainWindow::slotLayoutGuides(int state){ +void MainWindow::slotLayoutGuides(const bool &toggle){ qDebug()<< "MW:slotLayoutGuides()"; if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are node nodes yet!\nLoad a network file or create a new network first. \nThen we can talk about layouts!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("There are node nodes yet!\n" + "Load a network file or create a new network first."), "OK",0); statusMessage( tr("I am really sorry. You must really load a file first... ") ); - //layoutGuidesBx->setCheckState(Qt::Unchecked); return; } - if (state){ + if (toggle){ + toolBoxLayoutGuidesBx->setCheckState(Qt::Checked); + layoutGuidesAct->setChecked(true); qDebug()<< "MW:slotLayoutGuides() - will be displayed"; statusMessage( tr("Layout Guides will be displayed") ); } else { + toolBoxLayoutGuidesBx->setCheckState(Qt::Unchecked); + layoutGuidesAct->setChecked(false); qDebug()<< "MW:slotLayoutGuides() - will NOT be displayed"; graphicsWidget->clearGuides(); statusMessage( tr("Layout Guides will not be displayed") ); @@ -5876,7 +7775,7 @@ void MainWindow::slotLayoutGuides(int state){ /** - * @brief MainWindow::slotLayoutCircularByProminenceIndex + * @brief * Checks sender text() to find out who QMenu item was pressed * calls slotLayoutCircularByProminenceIndex(QString) */ @@ -5904,7 +7803,7 @@ void MainWindow::slotLayoutCircularByProminenceIndex(){ /** - * @brief MainWindow::slotLayoutCircularByProminenceIndex + * @brief * Overloaded - called when selectbox changes in the toolbox * or from slotLayoutCircularByProminenceIndex() when the user click on menu * Repositions all nodes on a Circular layout based on that index @@ -5923,7 +7822,7 @@ void MainWindow::slotLayoutCircularByProminenceIndex(QString choice=""){ } int userChoice = 0; QString prominenceIndexName = choice; - + slotLayoutGuides(true); if ( prominenceIndexName.contains("Degree Centrality") ) userChoice=1; else if ( prominenceIndexName == "Closeness Centrality") @@ -6050,10 +7949,16 @@ void MainWindow::slotLayoutCircularByProminenceIndex(QString choice=""){ double x0=scene->width()/2.0; double y0=scene->height()/2.0; - double maxRadius=(graphicsWidget->height()/2.0)-50; //pixels - statusMessage( QString(tr("Calculating new nodes positions. Please wait...")) ); + double maxRadius=(graphicsWidget->height()/2.0)-80; //pixels + graphicsWidget->clearGuides(); - createProgressBar(); + + statusMessage( tr("Embedding Prominence Index Circular Layout. Please wait...") ); + progressMsg = tr("Embedding Prominence Index Circular Layout. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.layoutCircularByProminenceIndex( x0, y0, maxRadius, userChoice, considerWeights, inverseWeights, @@ -6067,7 +7972,7 @@ void MainWindow::slotLayoutCircularByProminenceIndex(QString choice=""){ /** - * @brief MainWindow::slotLayoutNodeSizesByProminenceIndex + * @brief * Called when selectbox changes in the toolbox */ void MainWindow::slotLayoutNodeSizesByProminenceIndex(QString choice=""){ @@ -6208,9 +8113,13 @@ void MainWindow::slotLayoutNodeSizesByProminenceIndex(QString choice=""){ askAboutWeights(); - statusMessage( QString(tr("Calculating new node sizes. Please wait...")) ); graphicsWidget->clearGuides(); - createProgressBar(); + statusMessage( tr("Embedding Prominence Index Node Layout. Please wait...") ); + progressMsg = tr("Embedding Prominence Index Node Layout. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.layoutVerticesSizeByProminenceIndex( userChoice, considerWeights, inverseWeights, filterIsolateNodesAct->isChecked() || dropIsolates); @@ -6221,7 +8130,7 @@ void MainWindow::slotLayoutNodeSizesByProminenceIndex(QString choice=""){ /** - * @brief MainWindow::slotLayoutLevelByProminenceIndex + * @brief * Checks sender text() to find out who QMenu item was pressed * and what prominence index was chosen * calls slotLayoutLevelByProminenceIndex(QString) @@ -6276,7 +8185,7 @@ void MainWindow::slotLayoutLevelByProminenceIndex(QString choice=""){ } int userChoice = 0; QString prominenceIndexName = choice; - + slotLayoutGuides(true); if (prominenceIndexName == "Degree Centrality") userChoice=1; else if (prominenceIndexName == "Closeness Centrality") @@ -6400,18 +8309,26 @@ void MainWindow::slotLayoutLevelByProminenceIndex(QString choice=""){ } askAboutWeights(); + double maxWidth=scene->width(); - double maxHeight=scene->height(); //pixels - statusMessage( QString(tr("Calculating new nodes positions. Please wait...")) ); + + double maxHeight=scene->height(); + graphicsWidget->clearGuides(); - createProgressBar(); + + statusMessage( tr("Embedding Prominence Index Level Layout. Please wait...") ); + progressMsg = tr("Embedding Prominence Index Level Layout. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.layoutLevelByProminenceIndex( maxWidth, maxHeight, userChoice, considerWeights, inverseWeights, filterIsolateNodesAct->isChecked() || dropIsolates); destroyProgressBar(); statusMessage( tr("Nodes in upper levels are more prominent. ") ); - } +} /** @@ -6419,7 +8336,7 @@ void MainWindow::slotLayoutLevelByProminenceIndex(QString choice=""){ */ int MainWindow::activeEdges(){ qDebug () << "MW::activeEdges()"; - return activeGraph.enabledEdges(); + return activeGraph.edgesEnabled(); } @@ -6475,18 +8392,17 @@ void MainWindow::slotInvertAdjMatrix(){ } int aNodes=activeNodes(); statusBar() -> showMessage ( QString (tr ("inverting adjacency adjacency matrix of %1 nodes")).arg(aNodes) ); - qDebug ("MW: calling Graph::writeInvertAdjacencyMatrix with %i nodes", aNodes); - QString fn = dataDir + "socnetv-report-invert-adjacency-matrix.dat"; + qDebug ("MW: calling Graph::writeAdjacencyMatrixInvert with %i nodes", aNodes); + QString fn = appSettings["dataDir"] + "socnetv-report-invert-adjacency-matrix.dat"; QTime timer; timer.start(); - activeGraph.writeInvertAdjacencyMatrix(fn, networkName, QString("lu")) ; + activeGraph.writeAdjacencyMatrixInvert(fn, networkName, QString("lu")) ; int msecs = timer.elapsed(); statusMessage (QString(tr("Ready.")) + QString(" Time: ") + QString::number(msecs) ); //Open a text editor window for the new file created by graph class TextEditor *ed = new TextEditor(fn); - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tr("View Adjacency Matrix - ") + tempFileNameNoPath.last()); + ed->setWindowTitle(tr("Inverse adjacency matrix saved as ") + fn); ed->show(); @@ -6602,9 +8518,19 @@ void MainWindow::slotGraphDistance(){ askAboutWeights(); + + statusMessage( QString(tr("Computing Graph Distance. Please wait...")) ); + progressMsg = tr("Computing Graph Distance. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + int distance = activeGraph.distance(i,j, considerWeights, inverseWeights); + + destroyProgressBar(); + if ( distance > 0 && distance < RAND_MAX) QMessageBox::information(this, tr("Distance"), tr("Network distance (") +QString::number(i)+", "+QString::number(j) @@ -6631,26 +8557,27 @@ void MainWindow::slotDistancesMatrix(){ return; } statusMessage( tr("Creating distance matrix. Please wait...") ); - QString fn = dataDir + "socnetv-report-distance-matrix.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-distance-matrix.dat"; askAboutWeights(); - createProgressBar(); + statusMessage( tr("Computing Distances Matrix. Please wait...") ); + progressMsg = tr("Computing Distances Matrix. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.writeDistanceMatrix(fn, networkName.toLocal8Bit(), considerWeights, inverseWeights, filterIsolateNodesAct->isChecked()); destroyProgressBar(); - //Open a text editor window for the new file created by graph class TextEditor *ed = new TextEditor(fn); - tempFileNameNoPath=fn.split( "/"); - - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Distance matrix saved as: ")+tempFileNameNoPath.last()); + + statusMessage(tr("Distance matrix saved as: ")+fn); } @@ -6667,27 +8594,25 @@ void MainWindow::slotGeodesicsMatrix(){ return; } - QString fn = dataDir + "socnetv-report-sigmas-matrix.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-sigmas-matrix.dat"; askAboutWeights(); - statusMessage( tr("Creating number of geodesics matrix. Please wait...") ); - createProgressBar(); + statusMessage( tr("Computing Geodesics Matrix. Please wait...") ); + progressMsg = tr("Computing Geodesics Matrix. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeNumberOfGeodesicsMatrix(fn, networkName.toLocal8Bit(), considerWeights, inverseWeights); destroyProgressBar(); - //Open a text editor window for the new file created by graph class - TextEditor *ed = new TextEditor(fn); - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Matrix of geodesic path counts saved as: ") - + tempFileNameNoPath.last()); + + statusMessage(tr("Matrix of geodesic path counts saved as: ") + fn); } @@ -6707,7 +8632,11 @@ void MainWindow::slotDiameter() { askAboutWeights(); - createProgressBar(); + statusMessage( QString(tr("Computing Graph Diameter. Please wait...")) ); + progressMsg = tr("Computing Graph Diameter. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); int netDiameter=activeGraph.diameter(considerWeights, inverseWeights); @@ -6734,8 +8663,7 @@ void MainWindow::slotDiameter() { tr("\n\nSince this is a non-weighted network, \n" "the diameter is always less than N-1."), "OK",0); - statusMessage( tr("Diameter calculated. Ready.") ); - + statusMessage( tr("Graph Diameter computed. Ready.") ); } @@ -6753,14 +8681,21 @@ void MainWindow::slotAverageGraphDistance() { askAboutWeights(); - createProgressBar(); + statusMessage( QString(tr("Computing Average Graph Distance. Please wait...")) ); + progressMsg = tr("Computing Average Graph Distance. \n" + "Please wait (or disable progress bars from Options -> Settings)."); - float averGraphDistance=activeGraph.averageGraphDistance( + createProgressBar(0,progressMsg); + + float averGraphDistance=activeGraph.distanceGraphAverage( considerWeights, inverseWeights, filterIsolateNodesAct->isChecked() ); destroyProgressBar(); - QMessageBox::information(this, "Average Graph Distance", "The average shortest path length is = " + QString::number(averGraphDistance), "OK",0); + QMessageBox::information(this, + "Average Graph Distance", + "The average shortest path length is = " + + QString::number(averGraphDistance), "OK",0); statusMessage( tr("Average distance calculated. Ready.") ); } @@ -6776,23 +8711,24 @@ void MainWindow::slotEccentricity(){ statusMessage( QString(tr(" Nothing to do...")) ); return; } - QString fn = dataDir + "socnetv-report-eccentricity.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-eccentricity.dat"; askAboutWeights(); - statusMessage( QString(tr(" Please wait..."))); - createProgressBar(); + statusMessage( QString(tr("Computing Eccentricity. Please wait...")) ); + progressMsg = tr("Computing Eccentricity. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeEccentricity( fn, considerWeights, inverseWeights, filterIsolateNodesAct->isChecked()); destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Eccentricity report saved as: ") + tempFileNameNoPath.last()); + + statusMessage(tr("Eccentricity report saved as: ") + fn ); } @@ -6810,7 +8746,11 @@ void MainWindow::slotConnectedness(){ return; } - createProgressBar(); + statusMessage( QString(tr("Computing Connectedness. Please wait...")) ); + progressMsg = tr("Computing Connectedness. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); int connectedness=activeGraph.connectedness(); @@ -6875,42 +8815,57 @@ void MainWindow::slotWalksOfGivenLength(){ return; } - QString fn = dataDir + "socnetv-report-number-of-walks.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-number-of-walks.dat"; bool ok=false; - createProgressBar(); int length = QInputDialog::getInt(this, "Number of walks", tr("Select desired length of walk: (2 to %1)").arg(activeNodes()-1),2, 2, activeNodes()-1, 1, &ok ); if (!ok) { statusMessage( "Cancelled." ); return; } + statusMessage( QString(tr("Computing Walks of given length Matrix. Please wait...")) ); + progressMsg = tr("Computing Walks of given length Matrix. \n" + "Please wait (or disable progress bars from Options -> Settings)."); - activeGraph.writeNumberOfWalksMatrix(fn, networkName, length); + createProgressBar(0,progressMsg); + + activeGraph.writeWalksOfLengthMatrix(fn, networkName, length); destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Number of walks saved as: ") + tempFileNameNoPath.last()); + + statusMessage(tr("Number of walks saved as: ") + fn ); } /** -* Calls Graph:: writeTotalNumberOfWalksMatrix() to calculate and print -* the total number of walks of any length , between each pair of nodes. -*/ + * @brief MainWindow::slotTotalWalks +* Calls Graph:: writeWalksTotalMatrix() to calculate and print +* the total number of walks of any length , between each pair of nodes. + */ void MainWindow::slotTotalWalks(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to do! \nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); - statusMessage( QString(tr(" No network here. Sorry. Nothing to do.")) ); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); + statusMessage( QString(tr("Nothing to do.")) ); return; } if (activeNodes() > 50) { - switch( QMessageBox::critical(this, "Slow function warning",tr("Please note that this function is VERY SLOW on large networks (n>50), since it will calculate all powers of the sociomatrix up to n-1 in order to find out all possible walks. \n\nIf you need to make a simple reachability test, we advise to use the Reachability Matrix function instead. \n\n Are you sure you want to continue?"), QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel) ) { + switch( QMessageBox::critical( + this, + "Slow function warning", + tr("Please note that this function is VERY SLOW on large networks (n>50), " + "since it will calculate all powers of the sociomatrix up to n-1 " + "in order to find out all possible walks. \n\n" + "If you need to make a simple reachability test, " + "we advise to use the Reachability Matrix function instead. \n\n " + "Are you sure you want to continue?"), + QMessageBox::Ok|QMessageBox::Cancel,QMessageBox::Cancel) ) { case QMessageBox::Ok: break; @@ -6923,20 +8878,22 @@ void MainWindow::slotTotalWalks(){ break; } } - QString fn = dataDir + "socnetv-report-total-number-of-walks.dat"; - createProgressBar(); - + QString fn = appSettings["dataDir"] + "socnetv-report-total-number-of-walks.dat"; int maxLength=activeNodes()-1; - activeGraph.writeTotalNumberOfWalksMatrix(fn, networkName, maxLength); - destroyProgressBar(); + statusMessage( QString(tr("Computing Total Walks Matrix. Please wait...")) ); + progressMsg = tr("Computing Total Walks Matrix. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(maxLength,progressMsg); + + activeGraph.writeWalksTotalMatrix(fn, networkName, maxLength); + destroyProgressBar(maxLength); // do not check for progress bar TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle( tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage("Total number of walks saved as: " + tempFileNameNoPath.last()); + + statusMessage("Total number of walks saved as: " + fn); } @@ -6947,26 +8904,31 @@ void MainWindow::slotTotalWalks(){ * the Reachability Matrix of the network. */ void MainWindow::slotReachabilityMatrix(){ - if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to do! \nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); - statusMessage( QString(tr(" No network here. Sorry. Nothing to do.")) ); + if (!fileLoaded && !networkModified ) { + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); + statusMessage( QString(tr("Nothing to do.")) ); return; } - QString fn = dataDir + "socnetv-report-reachability-matrix.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-reachability-matrix.dat"; - createProgressBar(); + statusMessage( QString(tr("Computing Reachability Matrix. Please wait...")) ); + progressMsg = tr("Computing Reachability Matrix. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeReachabilityMatrix(fn, networkName); destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage("Reachability Matrix saved as: " + tempFileNameNoPath.last()); + + statusMessage("Reachability Matrix saved as: " + fn ); } /** @@ -6975,25 +8937,30 @@ void MainWindow::slotReachabilityMatrix(){ */ void MainWindow::slotCliqueCensus(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to do! \nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" No network here. Sorry. Nothing to do.")) ); return; } - QString fn = dataDir + "socnetv-report-clique-census.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-clique-census.dat"; bool considerWeights=true; - createProgressBar(); + statusMessage( QString(tr("Computing Clique Census. Please wait...")) ); + progressMsg = tr("Computing Clique Census. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeCliqueCensus(fn, considerWeights); destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage("Clique Census saved as: " + tempFileNameNoPath.last()); + + statusMessage("Clique Census saved as: " + fn); } @@ -7006,25 +8973,30 @@ void MainWindow::slotCliqueCensus(){ */ void MainWindow::slotClusteringCoefficient (){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to do! \nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" No network here. Sorry. Nothing to do.")) ); return; } - QString fn = dataDir + "socnetv-report-clustering-coefficients.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-clustering-coefficients.dat"; bool considerWeights=true; - createProgressBar(); + statusMessage( QString(tr("Computing Clustering Coefficient. Please wait...")) ); + progressMsg = tr("Computing Clustering Coefficient. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeClusteringCoefficient(fn, considerWeights); destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage("Clustering Coefficients saved as: " + tempFileNameNoPath.last()); + + statusMessage("Clustering Coefficients saved as: " + fn); } @@ -7036,25 +9008,30 @@ void MainWindow::slotClusteringCoefficient (){ void MainWindow::slotTriadCensus() { if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to do! \nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" No network here. Sorry. Nothing to do.")) ); return; } - QString fn = dataDir + "socnetv-report-triad-census.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-triad-census.dat"; bool considerWeights=true; - createProgressBar(); + statusMessage( QString(tr("Computing Triad Census. Please wait...")) ); + progressMsg = tr("Computing Triad Census. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeTriadCensus(fn, considerWeights); destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage("Triad Census saved as: " + tempFileNameNoPath.last()); + + statusMessage("Triad Census saved as: " + fn); } @@ -7063,7 +9040,10 @@ void MainWindow::slotTriadCensus() { */ void MainWindow::slotCentralityDegree(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to do! \nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" No network here. Sorry. Nothing to do.")) ); return; } @@ -7087,9 +9067,13 @@ void MainWindow::slotCentralityDegree(){ } } - QString fn = dataDir + "socnetv-report-centrality-out-degree.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-centrality-out-degree.dat"; - createProgressBar(); + statusMessage( QString(tr("Computing Degree Centrality. Please wait...")) ); + progressMsg = tr("Computing Degree Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeCentralityDegree(fn, considerWeights, filterIsolateNodesAct->isChecked() ); @@ -7097,11 +9081,9 @@ void MainWindow::slotCentralityDegree(){ destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Out-Degree Centralities saved as: ") + tempFileNameNoPath.last()); + + statusMessage(tr("Out-Degree Centralities saved as: ") + fn); } @@ -7112,9 +9094,10 @@ void MainWindow::slotCentralityDegree(){ */ void MainWindow::slotCentralityCloseness(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are no nodes!\nLoad a network" - " file or create a new network manually. " - "\nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr("Nothing to do...")) ); return; } @@ -7184,9 +9167,13 @@ void MainWindow::slotCentralityCloseness(){ askAboutWeights(); - QString fn = dataDir + "socnetv-report-centrality_closeness.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_closeness.dat"; - createProgressBar(); + statusMessage( QString(tr("Computing Closeness Centrality. Please wait...")) ); + progressMsg = tr("Computing Closeness Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeCentralityCloseness( fn, considerWeights, inverseWeights, @@ -7195,11 +9182,9 @@ void MainWindow::slotCentralityCloseness(){ destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle( tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Closeness Centralities saved as: ") + tempFileNameNoPath.last()); + + statusMessage(tr("Closeness Centralities saved as: ") + fn); } @@ -7212,19 +9197,23 @@ void MainWindow::slotCentralityCloseness(){ */ void MainWindow::slotCentralityClosenessInfluenceRange(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are no nodes!\nLoad a network" - " file or create a new network manually. " - "\nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr("Nothing to do...")) ); return; } - QString fn = dataDir + "socnetv-report-centrality_closeness_influence_range.dat"; - + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_closeness_influence_range.dat"; askAboutWeights(); - createProgressBar(); + statusMessage( QString(tr("Computing Influence Range Centrality. Please wait...")) ); + progressMsg = tr("Computing Influence Range Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); activeGraph.writeCentralityClosenessInfluenceRange( fn, considerWeights,inverseWeights, @@ -7235,11 +9224,9 @@ void MainWindow::slotCentralityClosenessInfluenceRange(){ statusMessage( QString(tr(" displaying file..."))); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Influence Range Closeness Centrality saved as: ")+tempFileNameNoPath.last()); + + statusMessage(tr("Influence Range Closeness Centrality saved as: ")+fn); } @@ -7250,31 +9237,33 @@ void MainWindow::slotCentralityClosenessInfluenceRange(){ */ void MainWindow::slotCentralityBetweenness(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are no nodes!\nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); - + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" Nothing to do...")) ); return; } - QString fn = dataDir + "socnetv-report-centrality_betweenness.dat"; - + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_betweenness.dat"; askAboutWeights(); - statusMessage( QString(tr(" Please wait..."))); - createProgressBar(); + statusMessage( QString(tr("Computing Betweenness Centrality. Please wait...")) ); + progressMsg = tr("Computing Betweenness Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.writeCentralityBetweenness( fn, considerWeights, inverseWeights, filterIsolateNodesAct->isChecked()); - destroyProgressBar(); - statusMessage( QString(tr(" displaying file..."))); + destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last() ); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Betweenness Centralities saved as: ")+tempFileNameNoPath.last()); + + statusMessage(tr("Betweenness Centralities saved as: ")+fn); } @@ -7286,7 +9275,10 @@ void MainWindow::slotCentralityBetweenness(){ */ void MainWindow::slotPrestigeDegree(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("Nothing to do!\nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr("Nothing to do...")) ); return; } @@ -7321,9 +9313,13 @@ void MainWindow::slotPrestigeDegree(){ } } - QString fn = dataDir + "socnetv-report-degree-prestige.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-degree-prestige.dat"; + + statusMessage( QString(tr("Computing Degree Prestige . Please wait...")) ); + progressMsg = tr("Computing Degree Prestige. \n" + "Please wait (or disable progress bars from Options -> Settings)."); - createProgressBar(); + createProgressBar(0,progressMsg); activeGraph.writePrestigeDegree(fn, considerWeights, filterIsolateNodesAct->isChecked() ); @@ -7331,11 +9327,9 @@ void MainWindow::slotPrestigeDegree(){ destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle( tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Degree Prestige (in-degree) saved as: ") + tempFileNameNoPath.last()); + + statusMessage(tr("Degree Prestige (in-degree) saved as: ") + fn); } @@ -7345,34 +9339,42 @@ void MainWindow::slotPrestigeDegree(){ */ void MainWindow::slotPrestigePageRank(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are no nodes!\nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" Nothing to do...")) ); return; } - QString fn = dataDir + "socnetv-report-prestige_pagerank.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-prestige_pagerank.dat"; askAboutWeights(); - statusMessage( QString(tr(" Please wait..."))); - createProgressBar(); + statusMessage( QString(tr("Computing PageRank Prestige. Please wait...")) ); + progressMsg = tr("Computing PageRank Prestige. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.writePrestigePageRank(fn, filterIsolateNodesAct->isChecked()); + destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("PageRank Prestige indices saved as: ")+ tempFileNameNoPath.last()); + + statusMessage(tr("PageRank Prestige indices saved as: ")+ fn); } + /** -* Writes Proximity Prestige indices into a file, then displays them. -*/ + * @brief MainWindow::slotPrestigeProximity + * Writes Proximity Prestige indices into a file, then displays them. + */ void MainWindow::slotPrestigeProximity(){ if (!fileLoaded && !networkModified ) { QMessageBox::critical( @@ -7384,12 +9386,16 @@ void MainWindow::slotPrestigeProximity(){ statusMessage( QString(tr(" Nothing to do...")) ); return; } - QString fn = dataDir + "socnetv-report-centrality_proximity_prestige.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_proximity_prestige.dat"; askAboutWeights(); - statusMessage( QString(tr(" Please wait..."))); - createProgressBar(); + statusMessage( QString(tr("Computing Proximity Prestige. Please wait...")) ); + progressMsg = tr("Computing Proximity Prestige. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.writePrestigeProximity(fn, true, false , filterIsolateNodesAct->isChecked()); destroyProgressBar(); @@ -7397,27 +9403,24 @@ void MainWindow::slotPrestigeProximity(){ statusMessage( QString(tr(" displaying file..."))); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle( tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Proximity Prestige Centralities saved as: ")+ tempFileNameNoPath.last()); + + statusMessage(tr("Proximity Prestige Centralities saved as: ")+ fn); } /** -* Writes Informational Centralities into a file, then displays it. -*/ + * @brief MainWindow::slotCentralityInformation + * Writes Informational Centralities into a file, then displays it. + */ void MainWindow::slotCentralityInformation(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical( - this, - "Error", - tr("There are no nodes!\n" - "Load a network file or create a new network. \n" - "Then ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" Nothing to do...")) ); return; } @@ -7446,379 +9449,186 @@ void MainWindow::slotCentralityInformation(){ break; } } - QString fn = dataDir + "socnetv-report-centrality_information.dat"; + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_information.dat"; statusMessage( QString(tr(" Please wait..."))); askAboutWeights(); - createProgressBar(); + + statusMessage( QString(tr("Computing Information Centrality. Please wait...")) ); + progressMsg = tr("Computing Information Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.writeCentralityInformation(fn,considerWeights, inverseWeights); + destroyProgressBar(); TextEditor *ed = new TextEditor(fn); - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Information Centralities saved as: ")+ tempFileNameNoPath.last()); + + statusMessage(tr("Information Centralities saved as: ")+ fn); } + /** -* Writes Stress Centralities into a file, then displays it. -*/ + * @brief MainWindow::slotCentralityStress + * Writes Stress Centralities into a file, then displays it. + */ void MainWindow::slotCentralityStress(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical( - this, - "Error", - tr("There are no nodes!\n" - "Load a network file or create a new network. \n" - "Then ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" Nothing to do! Why don't you try creating something first?")) ); return; } - QString fn = dataDir + "socnetv-report-centrality_stress.dat"; - + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_stress.dat"; askAboutWeights(); - statusMessage( QString(tr(" Please wait..."))); - createProgressBar(); + statusMessage( QString(tr("Computing Stress Centrality. Please wait...")) ); + progressMsg = tr("Computing Stress Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + createProgressBar(0,progressMsg); + activeGraph.writeCentralityStress( fn, considerWeights, inverseWeights, filterIsolateNodesAct->isChecked()); + destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Stress Centralities saved as: ")+ tempFileNameNoPath.last()); + + statusMessage(tr("Stress Centralities saved as: ")+ fn); } + /** -* Writes Power Centralities into a file, then displays it. -*/ + * @brief MainWindow::slotCentralityPower + * Writes Power Centralities into a file, then displays it. + */ void MainWindow::slotCentralityPower(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are no nodes!\nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" Nothing to do! Why don't you try creating something first?")) ); return; } - QString fn = dataDir + "socnetv-report-centrality_power.dat"; - + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_power.dat"; askAboutWeights(); - statusMessage( QString(tr(" Please wait..."))); - createProgressBar(); + statusMessage( QString(tr("Computing Power Centrality. Please wait...")) ); + progressMsg = tr("Computing Power Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.writeCentralityPower( fn, considerWeights, inverseWeights, filterIsolateNodesAct->isChecked()); + destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Stress Centralities saved as: ")+ tempFileNameNoPath.last()); + statusMessage(tr("Stress Centralities saved as: ")+ fn); } + + /** -* Writes Eccentricity Centralities into a file, then displays it. -*/ + * @brief MainWindow::slotCentralityEccentricity + * Writes Eccentricity Centralities into a file, then displays it. + */ void MainWindow::slotCentralityEccentricity(){ if (!fileLoaded && !networkModified ) { - QMessageBox::critical(this, "Error",tr("There are no nodes!\nLoad a network file or create a new network. \nThen ask me to compute something!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("Nothing to do! \n" + "Load a network file or create a new network. \n" + "Then ask me to compute something!"), "OK",0); statusMessage( QString(tr(" Nothing to do...")) ); return; } - QString fn = dataDir + "socnetv-report-centrality_eccentricity.dat"; - + QString fn = appSettings["dataDir"] + "socnetv-report-centrality_eccentricity.dat"; askAboutWeights(); - statusMessage( QString(tr(" Please wait..."))); - createProgressBar(); + statusMessage( QString(tr("Computing Eccentricity Centrality. Please wait...")) ); + progressMsg = tr("Computing Eccentricity Centrality. \n" + "Please wait (or disable progress bars from Options -> Settings)."); + + createProgressBar(0,progressMsg); + activeGraph.writeCentralityEccentricity( fn, considerWeights, inverseWeights, filterIsolateNodesAct->isChecked()); + destroyProgressBar(); TextEditor *ed = new TextEditor(fn); //OPEN A TEXT EDITOR WINDOW - tempFileNameNoPath=fn.split( "/"); - ed->setWindowTitle(tempFileNameNoPath.last()); ed->show(); - QApplication::restoreOverrideCursor(); - statusMessage(tr("Eccentricity Centralities saved as: ")+ tempFileNameNoPath.last()); -} - - - -void MainWindow::createProgressBar(){ - - if (showProgressBarAct->isChecked() || activeEdges() > 2000){ - progressDialog= new QProgressDialog("Please wait....", "Cancel", 0, activeGraph.vertices(), this); - progressDialog -> setWindowModality(Qt::WindowModal); - connect( &activeGraph, SIGNAL( updateProgressDialog(int) ), progressDialog, SLOT(setValue(int) ) ) ; - progressDialog->setMinimumDuration(0); - } - - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - -} - - -void MainWindow::destroyProgressBar(){ - QApplication::restoreOverrideCursor(); - - if (showProgressBarAct->isChecked() || activeEdges() > 1000) - progressDialog->deleteLater(); -} - - - - -/** -* Called from Graph:: -*/ -bool MainWindow::showNumbers(){ - return displayNodeNumbersAct->isChecked(); -} - - - - - -/** -* Turns on/off displaying the numbers of nodes (outside ones) -*/ -void MainWindow::slotDisplayNodeNumbers(bool toggle) { - if (!fileLoaded && ! networkModified) { - QMessageBox::critical(this, "Error",tr("There are no nodes! \nLoad a network file or create a new network."), "OK",0); - statusMessage( tr("Errr...no nodes here. Sorry!") ); - return; - } - statusMessage( tr("Toggle Nodes Numbers. Please wait...") ); - - if (!toggle) { - graphicsWidget->setAllItemsVisibility(TypeNumber, false); - statusMessage( tr("Node Numbers are invisible now. Click the same option again to display them.") ); - return; - } - else{ - graphicsWidget->setAllItemsVisibility(TypeNumber, true); - statusMessage( tr("Node Numbers are visible again...") ); - } -} - - -/** -* Called by Graph:: and this->initNet() -*/ -bool MainWindow::showLabels(){ - return displayNodeLabelsAct->isChecked(); -} - - - -/** -* Called by Graph:: and this->initNet() -*/ -bool MainWindow::showNumbersInsideNodes(){ - return displayNumbersInsideNodesAct->isChecked(); -} - - - -/** -* Turns on/off displaying the nodenumbers inside the nodes. -*/ -void MainWindow::slotDisplayNumbersInsideNodes(bool toggle){ - statusMessage( tr("Toggle Numbers inside nodes. Please wait...") ); - - if ( showNumbers() ) { - // ? - } - else{ - displayNodeNumbersAct->setChecked(true); - } - - activeGraph.setShowNumbersInsideNodes(toggle); - graphicsWidget -> setNumbersInsideNodes(toggle); - - if (toggle){ - - statusMessage( tr("Numbers inside nodes...") ); - } - else { - - statusMessage( tr("Numbers outside nodes...") ); - } -} - -/** -* Turns on/off displaying labels -*/ -void MainWindow::slotDisplayNodeLabels(bool toggle){ - if (!fileLoaded && ! networkModified) { - QMessageBox::critical(this, "Error",tr("There are no nodes! \nLoad a network file or create a new network first. "), "OK",0); - statusMessage( tr("No nodes found. Sorry...") ); - return; - } - statusMessage( tr("Toggle Nodes Labels. Please wait...") ); - - if (!toggle) { - graphicsWidget->setAllItemsVisibility(TypeLabel, false); - statusMessage( tr("Node Labels are invisible now. Click the same option again to display them.") ); - return; - } - else{ - graphicsWidget->setAllItemsVisibility(TypeLabel, true); - statusMessage( tr("Node Labels are visible again...") ); - } - activeGraph.setShowLabels(toggle); -} - - - - -/** -* Changes the size of all nodes -*/ -void MainWindow::slotChangeAllNodesSize() { - bool ok=false; - - int newSize = QInputDialog::getInt( - this, - "Change node size", - tr("Select new size for all nodes: (1-16)"), - initNodeSize, 1, 16, 1, &ok ); - if (!ok) { - statusMessage( "Change node size operation cancelled." ); - return; - } - - qDebug ("MW: slotChangeAllNodesSize:"); - changeAllNodesSize(newSize); - graphChanged(); - statusBar()->showMessage (QString(tr("Ready")), statusBarDuration) ; - return; -} - - -/** -* Changes the size of nodes. -*/ -void MainWindow::changeAllNodesSize(int size) { - qDebug ("MW: changeAllNodesSize:"); - if (size == 0 ) { - if (activeNodes() < 200) { - return; - } - else if (activeNodes() >= 200 && activeNodes() < 500){ - size = 4; - } - else if (activeNodes() >= 500 && activeNodes() < 1000) { - size = 3; - } - else if (activeNodes() >= 1000) { - size = 2; - } - } - initNodeSize = size; - activeGraph.setAllVerticesSize(size); -} - - -/** -* Changes the shape of all nodes. -*/ -void MainWindow::slotChangeAllNodesShape() { - bool ok=false; - QStringList lst; - lst << "box"<< "circle"<< "diamond"<< "ellipse"<< "triangle"; - QString newShape = QInputDialog::getItem(this, "Node shapes", "Select a shape for all nodes: ", lst, 1, true, &ok); - if ( ok ) { - //user selected an item and pressed OK - QList list=scene->items(); - for (QList::iterator it=list.begin(); it!=list.end(); it++) - if ( (*it) -> type() == TypeNode ){ - Node *jim = (Node*) (*it); - (*jim).setShape(newShape); - activeGraph.setVertexShape ((*jim).nodeNumber(), newShape); - } - graphChanged(); - activeGraph.setInitVertexShape(newShape); - statusBar()->showMessage (QString(tr("All shapes have been changed. Ready")), statusBarDuration) ; - } else { - //user pressed Cancel - statusBar()->showMessage (QString(tr("Change node shapes aborted...")), statusBarDuration) ; - } + statusMessage(tr("Eccentricity Centralities saved as: ")+ fn); } /** -* Change size of all nodes' numbers (outside ones) -*/ -void MainWindow::slotChangeNumbersSize() { - bool ok=false; - int newSize; - newSize = QInputDialog::getInt(this, "Change text size", tr("Change all nodenumbers size to: (1-16)"),initNumberSize, 1, 16, 1, &ok ); - if (!ok) { - statusMessage( tr("Change font size: Aborted.") ); - return; + * @brief MainWindow::createProgressBar + * @param max + * @param msg + * Creates a Qt Progress Dialog + * if max = 0, then max becomes equal to active vertices* + */ +void MainWindow::createProgressBar(const int &max, const QString &msg){ + qDebug() << "MW::createProgressBar" ; + + if ( appSettings["showProgressBar"] == "true" ){ + progressDialog = new QProgressDialog(msg, + "Cancel", + 0, + (max==0) ? activeGraph.vertices(): max + , this); + progressDialog -> setWindowModality(Qt::WindowModal); + connect( &activeGraph, SIGNAL( updateProgressDialog(int) ), + progressDialog, SLOT(setValue(int) ) ) ; + progressDialog->setMinimumDuration(0); } - QList list=scene->items(); - for (QList::iterator it2=list.begin();it2!=list.end(); it2++) - - if ( (*it2)->type()==TypeNumber) { - NodeNumber * number= (NodeNumber*) (*it2); - qDebug ("MW: slotChangeNumbersSize Found"); - number->setFont( QFont (number->font().family(), newSize, QFont::Light, false) ); - } + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - activeGraph.setInitVertexNumberSize(newSize); - statusMessage( tr("Changed numbers size. Ready.") ); } /** -* Changes size of all nodes' labels -*/ -void MainWindow::slotChangeLabelsSize() { - bool ok=false; - int newSize; - newSize = QInputDialog::getInt(this, "Change text size", tr("Change all node labels size to: (1-16)"),initNumberSize, 1, 16, 1, &ok ); - if (!ok) { - statusMessage( tr("Change font size: Aborted.") ); - return; - } - QList list=scene->items(); - for (QList::iterator it2=list.begin();it2!=list.end(); it2++) - - if ( (*it2)->type()==TypeLabel) { - NodeLabel *label= (NodeLabel*) (*it2); - qDebug ("MW: slotChangeLabelsSize Found"); - label->setFont( QFont (label->font().family(), newSize, QFont::Light, false) ); - activeGraph.setVertexLabelSize ( (label->node())->nodeNumber(), newSize); + * @brief MainWindow::destroyProgressBar + */ +void MainWindow::destroyProgressBar(int max){ + qDebug () << "MainWindow::destroyProgressBar"; + QApplication::restoreOverrideCursor(); + qDebug () << "MainWindow::destroyProgressBar - check if a progressbar exists"; + if ( appSettings["showProgressBar"] == "true" && max > -1 ) { + if ( progressDialog->value() != 0 ) { + qDebug () << "MainWindow::destroyProgressBar - progressbar exists. Destroying"; + progressDialog->deleteLater(); } - activeGraph.setInitVertexLabelSize(newSize); - statusMessage( tr("Changed labels size. Ready.") ); + } } @@ -7826,85 +9636,126 @@ void MainWindow::slotChangeLabelsSize() { /** - Turns on/off drawing edges as thick as their weights. - TODO -*/ -void MainWindow::slotDrawEdgesThickAsWeights() { - + * @brief MainWindow::slotOptionsNodeNumbersVisibility + * Turns on/off displaying the numbers of nodes (outside ones) + * @param toggle + */ +void MainWindow::slotOptionsNodeNumbersVisibility(bool toggle) { + qDebug() << "MW::slotOptionsNodeNumbersVisibility()" << toggle; + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + statusMessage( tr("Toggle Nodes Numbers. Please wait...") ); + appSettings["initNodeNumbersVisibility"] = (toggle) ? "true":"false"; + graphicsWidget->setNodeNumberVisibility(toggle); + optionsNodeNumbersVisibilityAct->setChecked ( toggle ); + if (!toggle) { + statusMessage( tr("Node Numbers are invisible now. " + "Click the same option again to display them.") ); + } + else{ + statusMessage( tr("Node Numbers are visible again...") ); + } + QApplication::restoreOverrideCursor(); + return; } + /** -* Turns on/off displaying edge weight numbers -*/ -void MainWindow::slotDisplayEdgesWeightNumbers(bool toggle) { - if (!fileLoaded && ! networkModified) { - QMessageBox::critical(this, "Error",tr("There are no edges! \nLoad a network file or create a new network first."), "OK",0); - statusMessage( tr("No nodes or edges found. Sorry...") ); - return; - } - qDebug() << "MW::slotDisplayEdgesWeightNumbers - Toggling Edges Weights. Please wait..."; - statusMessage( tr("Toggle Edges Weights. Please wait...") ); + * @brief MainWindow::slotOptionsNodeNumbersInside + * Turns on/off displaying the nodenumbers inside the nodes. + * @param toggle + */ +void MainWindow::slotOptionsNodeNumbersInside(bool toggle){ + qDebug() << "MW::slotOptionsNodeNumbersInside()" << toggle; - if (!toggle) { - graphicsWidget->setAllItemsVisibility(TypeEdgeWeight, false); - statusMessage( tr("Edge weights are invisible now. Click the same option again to display them.") ); - return; + statusMessage( tr("Toggle Numbers inside nodes. Please wait...") ); + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + // if node numbers are hidden, show them first. + if ( toggle && appSettings["initNodeNumbersVisibility"] != "true" ) + slotOptionsNodeNumbersVisibility(true); + + appSettings["initNodeNumbersInside"] = (toggle) ? "true":"false"; + activeGraph.vertexNumbersInsideNodesSet(toggle); + graphicsWidget -> setNumbersInsideNodes(toggle); + optionsNodeNumbersVisibilityAct->setChecked (toggle); + if (toggle){ + statusMessage( tr("Numbers inside nodes...") ); } - else{ - graphicsWidget->setAllItemsVisibility(TypeEdgeWeight, true); - statusMessage( tr("Edge weights are visible again...") ); + else { + statusMessage( tr("Numbers outside nodes...") ); } - activeGraph.setShowLabels(toggle); + QApplication::restoreOverrideCursor(); } + + + /** - * @brief MainWindow::slotConsiderEdgeWeights + * @brief MainWindow::slotOptionsNodeLabelsVisibility + * Turns on/off displaying labels * @param toggle */ -void MainWindow::slotConsiderEdgeWeights(bool toggle) { - if (toggle) { - considerWeights=true; - askedAboutWeights=false; - askAboutWeights(); // will only ask about inversion - } - else - considerWeights=false; +void MainWindow::slotOptionsNodeLabelsVisibility(bool toggle){ + qDebug() << "MW::slotOptionsNodeLabelsVisibility()" << toggle; + + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + statusMessage( tr("Toggle Nodes Labels. Please wait...") ); + appSettings["initNodeLabelsVisibility"] = (toggle) ? "true":"false"; + graphicsWidget->setNodeLabelsVisibility(toggle); + activeGraph.vertexLabelsVisibilitySet(toggle); + optionsNodeLabelsVisibilityAct->setChecked ( toggle ); + if (!toggle) { + statusMessage( tr("Node Labels are invisible now. " + "Click the same option again to display them.") ); + } + else{ + statusMessage( tr("Node Labels are visible again...") ); + } + QApplication::restoreOverrideCursor(); } + + + + /** -* Turns on/off displaying edges -*/ -void MainWindow::slotDisplayEdges(bool toggle){ + * @brief MainWindow::slotOptionsEdgesVisibility + * @param toggle + */ +void MainWindow::slotOptionsEdgesVisibility(bool toggle){ if (!fileLoaded && ! networkModified) { - QMessageBox::critical(this, "Error",tr("There are no nodes nor edges! \nLoad a network file or create a new network first!"), "OK",0); + QMessageBox::critical(this, "Error", + tr("There are no nodes nor edges! \n" + "Load a network file or create a new network first!"), "OK",0); statusMessage( tr("No edges found...") ); return; } + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); statusMessage( tr("Toggle Edges Arrows. Please wait...") ); - + appSettings["initEdgesVisibility"] = (toggle) ? "true": "false"; + graphicsWidget->setAllItemsVisibility(TypeEdge, toggle); if (!toggle) { - graphicsWidget->setAllItemsVisibility(TypeEdge, false); statusMessage( tr("Edges are invisible now. Click again the same menu to display them.") ); - return; } else{ - graphicsWidget->setAllItemsVisibility(TypeEdge, true); statusMessage( tr("Edges visible again...") ); } - + QApplication::restoreOverrideCursor(); } + /** -* Turns on/off the arrows of edges -*/ -void MainWindow::slotDisplayEdgesArrows(bool toggle){ + * @brief MainWindow::slotOptionsEdgeArrowsVisibility + * Turns on/off the arrows of edges + * @param toggle + */ +void MainWindow::slotOptionsEdgeArrowsVisibility(bool toggle){ if (!fileLoaded && ! networkModified) { QMessageBox::critical(this, "Error",tr("There are no edges! \nLoad a network file or create a new network first!"), "OK",0); @@ -7912,8 +9763,10 @@ void MainWindow::slotDisplayEdgesArrows(bool toggle){ return; } statusMessage( tr("Toggle Edges Arrows. Please wait...") ); + appSettings["initEdgeArrows"]= (toggle) ? "true":"false"; if (!toggle) { + QList list = scene->items(); for (QList::iterator item=list.begin();item!=list.end(); item++) { if ( (*item)->type() ==TypeEdge){ @@ -7924,6 +9777,7 @@ void MainWindow::slotDisplayEdgesArrows(bool toggle){ return; } else{ + appSettings["initEdgeArrows"]="true"; QList list = scene->items(); for (QList::iterator item=list.begin();item!=list.end(); item++) if ( (*item)->type() ==TypeEdge){ @@ -7936,10 +9790,28 @@ void MainWindow::slotDisplayEdgesArrows(bool toggle){ + + +/** + * @brief MainWindow::slotOptionsEdgeWeightsDuringComputation + * @param toggle + */ +void MainWindow::slotOptionsEdgeWeightsDuringComputation(bool toggle) { + if (toggle) { + considerWeights=true; + askedAboutWeights=false; + askAboutWeights(); // will only ask about inversion + } + else + considerWeights=false; +} + + + /** * FIXME edges Bezier */ -void MainWindow::slotDrawEdgesBezier(bool toggle){ +void MainWindow::slotOptionsEdgesBezier(bool toggle){ if (!fileLoaded && ! networkModified) { QMessageBox::critical(this, "Error",tr("There are no edges! \nLoad a network file or create a new network!"), "OK",0); @@ -7978,95 +9850,85 @@ void MainWindow::slotDrawEdgesBezier(bool toggle){ } - /** -* Changes the background color of the scene -*/ -void MainWindow::slotBackgroundColor () { - qDebug("MW: slotBackgroundColor "); - QColor backgrColor = QColorDialog::getColor( initBackgroundColor, this ); - graphicsWidget ->setBackgroundBrush(QBrush(backgrColor)); - statusMessage( tr("Ready. ") ); -} - - + * @brief MainWindow::slotOptionsEdgeThicknessPerWeight + * @param toggle + */ +void MainWindow::slotOptionsEdgeThicknessPerWeight(bool toogle) { + if (toogle) { -/** -* Changes the color of all edges -*/ -void MainWindow::slotAllEdgesColor(){ - QColor color = QColorDialog::getColor( Qt::red, this, - "Change the color of all nodes" ); - if (color.isValid()) { - initNodeColor=color.name(); - QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - qDebug() << "MainWindow::slotAllEdgesColor() : " << initNodeColor; - //createProgressBar(); - activeGraph.setAllEdgesColor(initNodeColor); - //destroyProgressBar(); - QApplication::restoreOverrideCursor(); - graphChanged(); - statusMessage( tr("Ready. ") ); } else { - // user pressed Cancel - statusMessage( tr("Nodes color change aborted. ") ); + } } -/** -* Changes the color of nodes' numbers -*/ -void MainWindow::slotAllNumbersColor(){ - QColor textColor = QColorDialog::getColor( Qt::black, this ); +/** + * @brief MainWindow::slotOptionsEdgeWeightNumbersVisibility + * Turns on/off displaying edge weight numbers + * @param toggle + */ +void MainWindow::slotOptionsEdgeWeightNumbersVisibility(bool toggle) { + qDebug() << "MW::slotOptionsEdgeWeightNumbersVisibility - Toggling Edges Weights"; QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - qDebug ("MW: Will change color"); - QList list= scene->items(); - for (QList::iterator it=list.begin(); it!=list.end(); it++) { - if ( (*it)->type() == TypeNumber) { - NodeNumber *jimNumber = (NodeNumber *) (*it); - jimNumber->update(); - jimNumber->setDefaultTextColor(textColor); - } + statusMessage( tr("Toggle Edges Weights. Please wait...") ); + appSettings["initEdgeWeightNumbersVisibility"] = (toggle) ? "true":"false"; + graphicsWidget->setEdgeWeightNumbersVisibility(toggle); + activeGraph.edgeWeightNumbersVisibilitySet(toggle); + optionsEdgeWeightNumbersAct->setChecked ( toggle ); + if (!toggle) { + statusMessage( tr("Edge weights are invisible now. " + "Click the same option again to display them.") ); + } + else{ + statusMessage( tr("Edge weights are visible again...") ); } - activeGraph.setInitVertexNumberColor( textColor.name() ); QApplication::restoreOverrideCursor(); - statusMessage( tr("Numbers' colors changed. Ready. ") ); + } + + + + /** -* Changes the color of nodes labels -*/ -void MainWindow::slotAllLabelsColor(){ - QColor textColor = QColorDialog::getColor( Qt::black, this ); + * @brief MainWindow::slotOptionsEdgeLabelsVisibility + * Turns on/off displaying edge labels + * @param toggle + */ +void MainWindow::slotOptionsEdgeLabelsVisibility(bool toggle) { + qDebug() << "MW::slotOptionsEdgeLabelsVisibility - Toggling Edges Weights"; QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); - qDebug ("MW: Will change label color"); - QList list= scene->items(); - for (QList::iterator it=list.begin(); it!=list.end(); it++) - if ( (*it)->type() == TypeNode ) { - Node *jim = (Node *) (*it); - jim->label()->update(); - jim->label()->setDefaultTextColor(textColor); - qDebug ("MW: Changed color"); - activeGraph.setVertexLabelColor (jim->nodeNumber(), textColor.name()); - } - activeGraph.setInitVertexLabelColor(textColor.name()); + statusMessage( tr("Toggle Edges Labels. Please wait...") ); + + appSettings["initEdgeLabelsVisibility"] = (toggle) ? "true":"false"; + graphicsWidget->setEdgeLabelsVisibility(toggle); + activeGraph.edgeLabelsVisibilitySet(toggle); + optionsEdgeLabelsAct->setChecked ( toggle ); + if (!toggle) { + statusMessage( tr("Edge labels are invisible now. " + "Click the same option again to display them.") ); + } + else{ + statusMessage( tr("Edge labels are visible again...") ); + } QApplication::restoreOverrideCursor(); - statusMessage( tr("Label colors changed. Ready. ") ); -} +} /** -* turns antialiasing on or off -*/ -void MainWindow::slotAntialiasing(bool toggle) { + * @brief MainWindow::slotOptionsAntialiasing + * Turns antialiasing on or off + * @param toggle + */ +void MainWindow::slotOptionsAntialiasing(bool toggle) { statusMessage( tr("Toggle anti-aliasing. This will take some time if the network is large (>500)...") ); //Inform graphicsWidget about the change QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); @@ -8074,22 +9936,47 @@ void MainWindow::slotAntialiasing(bool toggle) { graphicsWidget->setRenderHint(QPainter::TextAntialiasing, toggle); graphicsWidget->setRenderHint(QPainter::SmoothPixmapTransform, toggle); QApplication::restoreOverrideCursor(); - if (!toggle) + if (!toggle) { statusMessage( tr("Anti-aliasing off.") ); - else + appSettings["antialiasing"] = "false"; + } + else { + appSettings["antialiasing"] = "true"; statusMessage( tr("Anti-aliasing on.") ); + } } + /** -* turn progressbar on or off -*/ -void MainWindow::slotShowProgressBar(bool toggle) { + * @brief MainWindow::slotOptionsEmbedLogoExporting + * + * @param toggle + */ +void MainWindow::slotOptionsEmbedLogoExporting(bool toggle){ + if (!toggle) { + statusMessage( tr("SocNetV logo print off.") ); + appSettings["printLogo"] = "false"; + } + else { + appSettings["printLogo"] = "true"; + statusMessage( tr("SocNetV logo print on.") ); + } +} + +/** + * @brief MainWindow::slotOptionsProgressBarVisibility + * @param toggle + * turn progressbar on or off + */ +void MainWindow::slotOptionsProgressBarVisibility(bool toggle) { statusMessage( tr("Toggle progressbar...")); if (!toggle) { + appSettings["showProgressBar"] = "false"; statusMessage( tr("Progress bars off.") ); } else { + appSettings["showProgressBar"] = "true"; statusMessage( tr("Progress bars on.") ); } } @@ -8097,14 +9984,18 @@ void MainWindow::slotShowProgressBar(bool toggle) { /** -* Turns debugging messages on or off -*/ -void MainWindow::slotPrintDebug(bool toggle){ + * @brief MainWindow::slotOptionsDebugMessages + * @param toggle + * Turns debugging messages on or off + */ +void MainWindow::slotOptionsDebugMessages(bool toggle){ if (!toggle) { + appSettings["printDebug"] = "false"; printDebug=false; statusMessage( tr("Debug messages off.") ); } else { + appSettings["printDebug"] = "true"; printDebug=true; statusMessage( tr("Debug messages on.") ); } @@ -8114,71 +10005,182 @@ void MainWindow::slotPrintDebug(bool toggle){ /** -* Turns Toolbar on or off -*/ -void MainWindow::slotViewToolBar(bool toggle) { + * @brief MainWindow::slotOptionsBackgroundColor + * Called from Options menu and Settings dialog + * @param color QColor + */ +void MainWindow::slotOptionsBackgroundColor (QColor color){ + + if (!color.isValid()) { + color = QColorDialog::getColor( QColor ( appSettings["initBackgroundColor"] ), + this, + "Change the background color" ); + } + if (color.isValid()) { + appSettings["initBackgroundColor"] = color.name(); + QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); + graphicsWidget ->setBackgroundBrush( + QBrush(QColor (appSettings["initBackgroundColor"])) + ); + QApplication::restoreOverrideCursor(); + statusMessage( tr("Ready. ") ); + } + else { + // user pressed Cancel + statusMessage( tr("Invalid color. ") ); + } + +} + + +/** + * @brief MainWindow::slotOptionsBackgroundImageSelect + * Toggles displaying a custom image in the background + * If toggle = true, presents a dialog to select an image file + * Called from app menu option + * @param toggle + */ +void MainWindow::slotOptionsBackgroundImageSelect(bool toggle) { + statusMessage( tr("Toggle BackgroundImage...")); + QString m_fileName ; + if (toggle == false) { + statusMessage( tr("BackgroundImage off.") ); + graphicsWidget->setBackgroundBrush( + QBrush(QColor (appSettings["initBackgroundColor"] ) ) + ); + } + else { + m_fileName = QFileDialog::getOpenFileName( + this, tr("Select one image"), getLastPath(), + tr("All (*);;PNG (*.png);;JPG (*.jpg)") + ); + if (m_fileName.isNull() ) + appSettings["initBackgroundImage"] = ""; + appSettings["initBackgroundImage"] = m_fileName; + slotOptionsBackgroundImage(); + } +} + + + +/** + * @brief MainWindow::slotOptionsBackgroundImage + * Enables/disables displaying a user-defined custom image in the background + * Called from Settings Dialog and + */ +void MainWindow::slotOptionsBackgroundImage() { + statusMessage( tr("Toggle BackgroundImage...")); + if (appSettings["initBackgroundImage"].isEmpty()) { + statusMessage( tr("BackgroundImage off.") ); + graphicsWidget->setBackgroundBrush( + QBrush(QColor (appSettings["initBackgroundColor"] ) ) + ); + } + else { + setLastPath(appSettings["initBackgroundImage"]); + graphicsWidget->setBackgroundBrush(QImage(appSettings["initBackgroundImage"])); + graphicsWidget->setCacheMode(QGraphicsView::CacheBackground); + statusMessage( tr("BackgroundImage on.") ); + } + + +} + + + + +/** + * @brief MainWindow::slotOptionsToolbarVisibility + * @param toggle + * Turns Toolbar on or off + */ +void MainWindow::slotOptionsToolbarVisibility(bool toggle) { statusMessage( tr("Toggle toolbar...")); if (toggle== false) { toolBar->hide(); + appSettings["showToolBar"] = "false"; statusMessage( tr("Toolbar off.") ); } else { toolBar->show(); + appSettings["showToolBar"] = "true"; statusMessage( tr("Toolbar on.") ); } } + /** -* Turns Statusbar on or off -*/ -void MainWindow::slotViewStatusBar(bool toggle) { + * @brief MainWindow::slotOptionsStatusBarVisibility + * @param toggle + * Turns Statusbar on or off + */ +void MainWindow::slotOptionsStatusBarVisibility(bool toggle) { statusMessage( tr("Toggle statusbar...")); if (toggle == false) { statusBar()->hide(); + appSettings["showStatusBar"] = "false"; statusMessage( tr("Status bar off.") ); } else { statusBar()->show(); + appSettings["showStatusBar"] = "true"; statusMessage( tr("Status bar on.") ); } } -/* - * Enables/disables displaying a user-defined custom image in the background +/** + * @brief MainWindow::slotOptionsLeftPanelVisibility + * @param toggle */ -void MainWindow::slotBackgroundImage(bool toggle) { - statusMessage( tr("Toggle BackgroundImage...")); - QString m_fileName ; +void MainWindow::slotOptionsLeftPanelVisibility(bool toggle) { + statusMessage( tr("Toggle left panel...")); + if (toggle == false) { - statusMessage( tr("BackgroundImage off.") ); - graphicsWidget->setBackgroundBrush(QBrush(initBackgroundColor)); + leftPanel->hide(); + appSettings["showLeftPanel"] = "false"; + statusMessage( tr("Left Panel off.") ); } else { - m_fileName = QFileDialog::getOpenFileName( - this, tr("Select one image"), getLastPath(), - tr("All (*);;PNG (*.png);;JPG (*.jpg)") - ); - if (!m_fileName.isEmpty()) { - setLastPath(m_fileName); - graphicsWidget->setBackgroundBrush(QImage(m_fileName)); - graphicsWidget->setCacheMode(QGraphicsView::CacheBackground); - statusMessage( tr("BackgroundImage on.") ); - } + leftPanel->show(); + appSettings["showLeftPanel"] = "true"; + statusMessage( tr("Left Panel on.") ); } +} + + +/** + * @brief MainWindow::slotOptionsRightPanelVisibility + * @param toggle + */ +void MainWindow::slotOptionsRightPanelVisibility(bool toggle) { + statusMessage( tr("Toggle left panel...")); + + if (toggle == false) { + rightPanel->hide(); + appSettings["showRightPanel"] = "false"; + statusMessage( tr("Right Panel off.") ); + } + else { + rightPanel->show(); + appSettings["showRightPanel"] = "true"; + statusMessage( tr("Right Panel on.") ); + } } + + /** * Displays a random tip */ -void MainWindow::slotTips() { - int randomTip=rand()%tipsCounter; //Pick a tip. +void MainWindow::slotHelpTips() { + int randomTip=rand() % (tips.count()); //Pick a tip. QMessageBox::about( this, tr("Tip Of The Day"), tips[randomTip]); } @@ -8187,25 +10189,81 @@ void MainWindow::slotTips() { /** Creates our tips. */ -void MainWindow::createTips(){ - tips+=tr("You can add a new node by double-clicking on the scene."); - tips+=tr("You can add a new node by clicking on Add button."); - tips+=tr("You can remove a node by clicking on Remove button."); - tips+=tr("You can rotate the network by selecting a new angle on the dock."); - tips+=tr("You can add a new edge between two nodes, by middle-clicking (or pressing both mouse buttons simultanesously) on the first and then on the second node."); - tips+=tr("You can remove a node by right-clicking on it and selecting Remove."); - tips+=tr("You can change background color (from the menu Edit > Colors)."); - tips+=tr("Nodes can have the colors of your choice. Just right-click on a node and then select > Options > Change Color. You can select every color supported by the X.org palette."); - tips+=tr("The tabs on the left dock show information about the network (nodes, edges, density, etc) as well as information about any node you clicked on (inDegrees, outDegrees, clustering)."); - tips+=tr("You can move a node easily by dragging it with your mouse."); - tips+=tr("SocNetV can save the positions of the nodes in a network, if you save it in Pajek/GraphML format."); - tips+=tr("You can apply layout algorithms on the network from the menu Layout or by clicking on the Dock > Layout tab checkboxes"); - tips+=tr("You can change the label of node by right-clicking on it, and selecting Options > Change Label."); - tips+=tr("All basic operations of SocNetV are available from the dock on the left, or by right-clicking on a node or an Edge."); - tips+=tr("Node information is displayed on the Status bar, when you left-click on it."); +void MainWindow::slotHelpCreateTips(){ + tips+=tr("To create a new node: \n" + "- double-click somewhere on the canvas \n" + "- or press the keyboard shortcut CTRL+. (dot)\n" + "- or press the Add Node button on the left panel"); + tips+=tr("SocNetV supports working with either undirected or directed data. " + "When you start SocNetV for the first time, the application uses " + "the 'directed data' mode; every edge you create is directed. " + "To enter the 'undirected data' mode, press CTRL+E+U or enable the " + "menu option Edit -> Edges -> Undirected Edges "); + tips+=tr("If your screen is small, and the canvas appears even smaller " + "hide the Control and/or Statistics panel. Then the canvas " + "will expand to the whole application window. " + "Open the Settings/Preferences dialog -> Window options and " + "disable the two panels."); + tips+=tr("A scale-free network is a network whose degree distribution follows a power law. " + "SocNetV generates random scale-free networks according to the " + "Barabási–Albert (BA) model using a preferential attachment mechanism."); + tips+=tr("To delete a node permanently: \n" + "- right-click on it and select Remove Node \n" + "- or press CTRL+ALT+. and enter its number\n" + "- or press the Remove Node button on the Control Panel"); + tips+=tr("To rotate the network: \n" + " - drag the bottom slider to left or right \n" + " - or click the buttons on the corners of the bottom slider\n" + " - or press CTRL and the left or right arrow."); + tips+=tr("To create a new edge between nodes A and B: \n" + "- double-click on node A, then double-click on node B.\n" + "- or middle-click on node A, and again on node B.\n" + "- or right-click on the node, then select Add Edge from the popup.\n" + "- or press the keyboard shortcut CTRL+/ \n" + "- or press the Add Edge button on the Control Panel"); + tips+=tr("Add a label to an edge by right-clicking on it " + "and selecting Change Label."); + tips+=tr("You can change the background color of the canvas. " + "Do it from the menu Options > View or " + "permanently save this setting in Settins/Preferences."); + tips+=tr("Default node colors, shapes and sizes can be changed. " + "Open the Settings/Preferences dialog and use the " + "options on the Node tab."); + tips+=tr("The Statistics Panel shows network-level information (i.e. density) " + "as well as info about any node you clicked on (inDegrees, " + "outDegrees, clustering)."); + tips+=tr("You can move any node by left-clicking and dragging it with your mouse. " + "If you want you can move multiple nodes at once. Left-click on empty space " + "on the canvas and drag to create a rectangle selection around them. " + "Then right-click on one of the selected nodes and drag it."); + tips+=tr("To save the node positions in a network, you need to save your data " + "in a format which supports node positions, suchs as GraphML or Pajek."); + tips+=tr("Embed visualization models on the network from the options in " + "the Layout menu or the select boxes on the left Control Panel. "); + tips+=tr("To change the label of a node right-click on it, and click " + "Selected Node Properties from the popup menu."); + tips+=tr("All basic operations of SocNetV are available from the left Control panel " + "or by right-clicking on a Node or an Edge or on canvas empty space."); + tips+=tr("Node info (number, position, degree, etc) is displayed on the Status bar, " + "when you left-click on it."); tips+=tr("Edge information is displayed on the Status bar, when you left-click on it."); - tipsCounter = 16; + tips+=tr("The Closeness Centrality (CC) of a node v, is the inverse sum of " + "the shortest distances between v and every other node. CC is " + "interpreted as the ability to access information through the " + "\'grapevine\' of network members. Nodes with high closeness " + "centrality are those who can reach many other nodes in few steps. " + "This index can be calculated in both graphs and digraphs. " + "It can also be calculated in weighted graphs although the weight of " + "each edge (v,u) in E is always considered to be 1. "); + + tips+=tr("The Information Centrality (IC) index counts all paths between " + "nodes weighted by strength of tie and distance. " + "This centrality measure developed by Stephenson and Zelen (1989) " + "focuses on how information might flow through many different paths. " + "This index should be calculated only for undirected graphs. " + "Note: To compute this index, SocNetV drops all isolated nodes."); + } @@ -8216,21 +10274,21 @@ void MainWindow::createTips(){ */ void MainWindow::slotHelp(){ - QString helpPath; + QString helpPath = ""; bool manualFound = false; QDir d( QCoreApplication::applicationDirPath() ); qDebug()<< QCoreApplication::applicationDirPath().toLatin1(); - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); } else { if (d.dirName()=="bin") { d.cdUp(); } if (d.cd("./manual") ) { - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); manualFound = true; } else { @@ -8241,8 +10299,8 @@ void MainWindow::slotHelp(){ // MacOS: assumes manual dir in socnetv.app/Contents/ // before deploy copy there the manual dir if (d.cd("../manual") ) { // for Mac - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); manualFound = true; } else { @@ -8252,8 +10310,8 @@ void MainWindow::slotHelp(){ } if (!manualFound && d.cd("../trunk/manual") ) { - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); manualFound = true; } else { @@ -8263,8 +10321,8 @@ void MainWindow::slotHelp(){ } if ( !manualFound && d.cd("/usr/local/share/doc/socnetv/") ) { //for compile installation if (d.exists("manual/")) d.cd("manual/"); - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); qDebug()<< "path" << helpPath.toLatin1(); manualFound = true; } @@ -8275,8 +10333,8 @@ void MainWindow::slotHelp(){ } if (!manualFound && d.cd("/usr/share/doc/socnetv/") ) { //for Debian Ubuntu if (d.exists("manual/")) d.cd("manual/"); - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); manualFound = true; } else { @@ -8287,8 +10345,8 @@ void MainWindow::slotHelp(){ if ( !manualFound && d.cd("/usr/share/doc/packages/socnetv/") ) { //for opensuse file hierarchy if (d.exists("manual/")) d.cd("manual/"); - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); manualFound = true; } else { @@ -8299,8 +10357,8 @@ void MainWindow::slotHelp(){ if ( !manualFound && d.cd(fedoraPath) ) { //for Fedora file hierarchy if (d.exists("manual/")) d.cd("manual/"); - if ( d.exists("manual.html") ) { - helpPath=d.filePath("manual.html"); + if ( d.exists("index.html") ) { + helpPath=d.filePath("index.html"); manualFound = true; } else { @@ -8311,26 +10369,36 @@ void MainWindow::slotHelp(){ } qDebug () << "help path is: " << helpPath.toLatin1(); - QDesktopServices::openUrl(QUrl::fromLocalFile(helpPath)); - + if ( manualFound == true) + QDesktopServices::openUrl(QUrl::fromLocalFile(helpPath)); + else + QDesktopServices::openUrl(QUrl("http://socnetv.sourceforge.net/docs/index.html")); } + +/** + * @brief MainWindow::slotHelpCheckUpdates + * Opens a web browser to SocNetV website. + */ +void MainWindow::slotHelpCheckUpdates() { + statusMessage( tr("Opening SocNetV website in your default web browser....") ); + QDesktopServices::openUrl(QUrl("http://socnetv.sourceforge.net/downloads?app=" + VERSION)); +} + /** Displays the following message!! */ void MainWindow::slotHelpAbout(){ - int randomCookie=rand()%fortuneCookiesCounter;//createFortuneCookies(); - - QString BUILD="Thu Jun 25 10:42:08 EEST 2015"; - + int randomCookie=rand()%fortuneCookie.count(); + QString BUILD="Mon Sep 12 10:36:40 EEST 2016"; QMessageBox::about( this, "About SocNetV", "Social Network Visualizer (SocNetV)" "

Version: " + VERSION + "

" "

Build: " + BUILD + "

" - "

(C) 2005-2015 by Dimitris V. Kalamaras" + "

(C) 2005-2016 by Dimitris V. Kalamaras" "
dimitris.kalamaras@gmail.com" "

Fortune cookie:
\"" + fortuneCookie[randomCookie] +"\"" @@ -8350,24 +10418,30 @@ void MainWindow::slotHelpAbout(){ Creates the fortune cookies displayed on the above message. */ void MainWindow::createFortuneCookies(){ - fortuneCookie+="sic itur ad astra / sic transit gloria mundi ?
--Unknown"; - fortuneCookie+="losers of yesterday, the winners of tomorrow...
--B.Brecht"; - fortuneCookie+="Patriotism is the virtue of the wicked...
--O. Wilde"; - + fortuneCookie+="sic itur ad astra / sic transit gloria mundi ?
" + "--Unknown"; + fortuneCookie+="Losers of yesterday, the winners of tomorrow...
" + "--B.Brecht"; + fortuneCookie+="Patriotism is the virtue of the wicked...
" + "--O. Wilde"; fortuneCookie+="No tengo nunca mas, no tengo siempre. En la arena
" "la victoria dejo sus piers perdidos.
" "Soy un pobre hombre dispuesto a amar a sus semejantes.
" - "No se quien eres. Te amo. No doy, no vendo espinas.
--Pablo Neruda" ; - fortuneCookie+="I will never apologize for the United States of America. I don't care what it has done. I don't care what the facts are.
--Vice President George H.W. Bush, after the Iranian airliner flight IR655 (an Airbus A300) was shot down by a U.S. missile cruiser (USS Vincennes), killing all 290 civilian passengers..."; - fortuneCookie+="Man must not check reason by tradition, but contrawise, must check tradition by reason.
--Leo Tolstoy"; - fortuneCookie+="Only after the last tree has been cut down,
only after the last river has been poisoned,
only after the last fish has been caught,
only then will you realize that money cannot be eaten.
--The Cree People"; - fortuneCookie+="Stat rosa pristina nomine, nomina nuda tenemus
--Unknown"; + "No se quien eres. Te amo. No doy, no vendo espinas.
" + "--Pablo Neruda" ; + fortuneCookie+="Man must not check reason by tradition, but contrawise, " + "must check tradition by reason.
--Leo Tolstoy"; + fortuneCookie+="Only after the last tree has been cut down,
" + "only after the last river has been poisoned,
" + "only after the last fish has been caught,
" + "only then will you realize that money cannot be eaten.
" + "--The Cree People"; + fortuneCookie+="Stat rosa pristina nomine, nomina nuda tenemus
" + " --Unknown"; fortuneCookie+="Jupiter and Saturn, Oberon, Miranda
" "And Titania, Neptune, Titan.
" "Stars can frighten.
Syd Barrett"; - fortuneCookiesCounter=9; - // return fortuneCookie.count(); } diff --git a/src/mainwindow.h b/src/mainwindow.h index e555576e..2fbb264e 100755 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -5,7 +5,7 @@ mainwindow.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -53,8 +53,8 @@ static const QString VERSION="2.0"; -using namespace std; +QT_BEGIN_NAMESPACE class QMenu; class QAction; class QCheckBox; @@ -63,17 +63,22 @@ class Edge; class Node; class QPushButton; +class QToolButton; class QLCDNumber; class QSlider; -class QComboBox; +class QComboBox; class QGroupBox; class QTabWidget; class QSpinBox; -class PreviewForm; +QT_END_NAMESPACE +using namespace std; + +class PreviewForm; class RandErdosRenyiDialog; class RandSmallWorldDialog; class RandScaleFreeDialog; +class SettingsDialog; /** @@ -100,134 +105,143 @@ class MainWindow : public QMainWindow void initToolBar(); void initToolBox(); void initStatusBar(); - void initNet(); void initView(); + void initWindowLayout(); + void initSignalSlots(); + QMap initSettings(); + void saveSettings(); + void initNet(); void setLastPath(QString filePath); QString getLastPath(); void createFortuneCookies(); - void createTips(); - - bool showLabels(); - bool showNumbersInsideNodes(); - bool showNumbers(); - - - /// \brief Main network file loader methods - bool previewNetworkFile(QString , int ); - - /// - /// \brief Main network file loader method - /// First, inits everything to default values. - /// Then calls activeGraph::loadGraph to actually load the network... - /// \param m_fileName - /// \param m_fileFormat - bool loadNetworkFile ( const QString, const QString, const int ); + void slotHelpCreateTips(); int activeEdges(); int activeNodes(); - void openContextMenu(const QPointF & mPos); - - void changeAllNodesSize(int size); - - QString initNodeColor; - int clickedJimNumber; //it is public because we need to be visible from activegraph. - - void createProgressBar(); - void destroyProgressBar(); + void createProgressBar(const int &max=0, const QString &msg="Please wait..."); + void destroyProgressBar(int max=0); public slots: - //FILE MENU - - /// \brief Creates a new network - void slotCreateNew(); - - /// \brief Prompts the user a directory dialogue to choose a file from. - /// Calls previewNetworkFile() - void slotChooseFile(); - void slotImportGraphML(); - void slotImportPajek(); - void slotImportSM(); - void slotImportDot(); - void slotImportGML(); - void slotImportDL(); - void slotImportEdgeList(); - void slotImportTwoModeSM(); - void slotFileSave(); - void slotFileSaveAs(); - void slotFileClose(); - void slotPrintView(); - bool slotExportBMP(); - bool slotExportPNG(); - bool slotExportPDF(); - void slotExportPajek(); - void slotExportSM(); - bool slotExportDL(); - bool slotExportGW(); - bool slotExportList(); //NETWORK MENU - void slotOpenTextEditor(); - void slotViewNetworkFile(); - - void findCodecs(); - void userCodec(const QString, const QString, const int ); - - void slotViewAdjacencyMatrix(); - void slotShowDataSetSelectDialog(); - void slotRecreateDataSet(QString); - void slotCreateRandomErdosRenyi(); - void createRandomNetErdos( const int N, + void slotNetworkNew(); + void slotNetworkFileChoose(QString m_fileName = QString::null, + int m_fileFormat = -1, + const bool &checkSelectFileType = true); + void slotNetworkFileRecentUpdateActions(); + void slotNetworkAvailableTextCodecs(); + bool slotNetworkFilePreview(const QString &, const int &); + bool slotNetworkFileLoad ( const QString, const QString, const int ); + void slotNetworkFileLoadRecent(); + + void slotNetworkFileView(); + void slotNetworkImportGraphML(); + void slotNetworkImportPajek(); + void slotNetworkImportSM(); + void slotNetworkImportDot(); + void slotNetworkImportGML(); + void slotNetworkImportDL(); + void slotNetworkImportEdgeList(); + void slotNetworkImportTwoModeSM(); + void slotNetworkChanged(); + void slotNetworkSave(); + void slotNetworkSaveAs(); + void slotNetworkClose(); + void slotNetworkPrint(); + void slotNetworkViewSociomatrix(); + bool slotNetworkExportBMP(); + bool slotNetworkExportPNG(); + bool slotNetworkExportPDF(); + void slotNetworkExportPajek(); + void slotNetworkExportSM(); + bool slotNetworkExportDL(); + bool slotNetworkExportGW(); + bool slotNetworkExportList(); + void slotNetworkTextEditor(); + void slotNetworkDataSetSelect(); + void slotNetworkDataSetRecreate(const QString); + + void slotRandomErdosRenyiDialog(); + void slotRandomErdosRenyi( const int N, const QString model, const int edges, const float eprob, const QString mode, const bool diag) ; - void slotCreateRegularRandomNetwork(); - void slotCreateRandomGaussian(); - void slotCreateRandomRingLattice(); - void slotCreateRandomScaleFree(); + void slotRandomRegularNetwork(); + + void slotRandomGaussian(); + + void slotRandomScaleFreeDialog(); - void createScaleFreeNetwork (const int &nodes, + void slotRandomScaleFree(const int &newNodes, const int &power, const int &initialNodes, const int &edgesPerStep, const float &zeroAppeal, const QString &mode); - void slotCreateRandomSmallWorld(); + void slotRandomSmallWorldDialog(); - void createSmallWorldNetwork (const int &nodes, + void slotRandomSmallWorld (const int &newNodes, const int °ree, const float &beta, const QString &mode, const bool &diag); - void slotShowWebCrawlerDialog(); - void slotWebCrawl(QString, int, int, bool, bool); - void prevRelation(); - void nextRelation(); - void addRelation(); - void addRelation(QString relationName); + void slotRandomRingLattice(); + + void slotNetworkWebCrawlerDialog(); + void slotNetworkWebCrawler(QString, int, int, bool, bool); //EDIT MENU - void slotSelectAll(); - void slotSelectNone(); - void slotFindNode(); - void slotAddEdge(); - void slotRemoveNode(); - void slotNodeProperties( const QString, const int, const QString, + void slotEditRelationPrev(); + void slotEditRelationNext(); + void slotEditRelationAdd(); + void slotEditRelationAdd(QString relationName); + + void slotEditOpenContextMenu(const QPointF & mPos); + + void slotEditClickOnEmptySpace (); + + void slotEditNodeSelectAll(); + void slotEditNodeSelectNone(); + + void slotEditNodeAdd(); + void slotEditNodeAddWithMouse(const QPointF &); + void slotEditNodeFind(); + void slotEditNodeRemove(); + void slotEditNodeOpenContextMenu(); + void slotEditNodePropertiesDialog(); + void slotEditNodeProperties( const QString, const int, const QString, const QColor, const QString); - void slotRemoveEdge(); - void slotChangeNodeProperties(); - void slotChangeEdgeLabel(); - void slotChangeEdgeColor(); - void slotChangeEdgeWeight(); + void slotEditNodeColorAll(QColor color=QColor()); + void slotEditNodeSizeAll(int newSize=0, const bool &normalized=false); + void slotEditNodeShape(QString shape=QString::null, const int vertex = 0); + void slotEditNodeNumberSize(int v1=0, int newSize=0, const bool prompt=true); + void slotEditNodeNumberDistance(int v1=0, int newSize=0); + void slotEditNodeNumbersColor(QColor color=QColor()); + void slotEditNodeLabelSize(int v1=0, int newSize=0); + void slotEditNodeLabelsColor(QColor color=QColor()); + void slotEditNodeLabelDistance(int v1=0, int newSize=0); + + void slotEditEdgeAdd(); + void slotEditEdgeCreate (const int &source, const int &target, const float &weight); + void slotEditEdgeRemove(); + void slotEditEdgeLabel(); + void slotEditEdgeColor(); + void slotEditEdgeWeight(); + void slotEditEdgeColorAll(QColor color=QColor(), const int &threshold=RAND_MAX); + void slotEditEdgeSymmetrizeAll(); + void slotEditEdgeUndirectedAll(const bool &toggle); + void slotFilterNodes(); void slotFilterIsolateNodes(bool checked); void slotShowFilterEdgesDialog(); void slotTransformNodes2Edges(); - void slotSymmetrize(); + + // LAYOUT MENU void slotColorationStrongStructural(); @@ -239,15 +253,11 @@ public slots: void slotLayoutNodeSizesByProminenceIndex(QString); void slotLayoutLevelByProminenceIndex(); void slotLayoutLevelByProminenceIndex(QString); - void slotLayoutGuides(int); - - - void slotLayoutSpringEmbedder(bool); + void slotLayoutGuides(const bool &toggle); + void slotLayoutSpringEmbedder(); void slotLayoutFruchterman(); - void layoutFruchterman(int); - - void slotLayoutNodeSizesByOutDegree(bool); - void slotLayoutNodeSizesByInDegree(bool); + void slotLayoutNodeSizesByOutDegree(bool); + void slotLayoutNodeSizesByInDegree(bool); //STATISTICS MENU void askAboutWeights(); @@ -283,56 +293,47 @@ public slots: void slotPrestigeProximity(); //OPTIONS MENU - void slotDisplayNodeNumbers(bool toggle); - void slotDisplayNodeLabels(bool toggle); - void slotDisplayNumbersInsideNodes(bool toggle); - void slotChangeAllNodesSize(); - void slotChangeAllNodesShape(); - void slotChangeNumbersSize(); - void slotChangeLabelsSize(); - void slotDrawEdgesThickAsWeights(); - void slotDrawEdgesBezier(bool toggle); - void slotDisplayEdgesWeightNumbers(bool toggle); - void slotConsiderEdgeWeights(bool); - void slotDisplayEdges(bool toggle); - void slotDisplayEdgesArrows(bool toggle); - - void slotBackgroundColor (); - void slotAllNodesColor(); - void slotAllEdgesColor(); - void slotAllNumbersColor(); - void slotAllLabelsColor(); - - //VIEW MENU - void slotAntialiasing(bool ); - void slotShowProgressBar(bool toggle); - void slotPrintDebug(bool toggle); - void slotViewToolBar(bool toggle); - void slotViewStatusBar(bool toggle); - void slotBackgroundImage(bool toggle); + void slotOpenSettingsDialog(); + void slotOptionsNodeNumbersVisibility(bool toggle); + void slotOptionsNodeNumbersInside(bool toggle); + void slotOptionsNodeLabelsVisibility(bool toggle); + void slotOptionsEdgesVisibility(bool toggle); + void slotOptionsEdgeLabelsVisibility(bool toggle); + void slotOptionsEdgeWeightNumbersVisibility(bool toggle); + void slotOptionsEdgeWeightsDuringComputation(bool); + void slotOptionsEdgeThicknessPerWeight(bool toogle); + void slotOptionsEdgesBezier(bool toggle); + void slotOptionsEdgeArrowsVisibility(bool toggle); + + void slotOptionsBackgroundColor(QColor color=QColor()); + void slotOptionsBackgroundImageSelect(bool toggle); + void slotOptionsBackgroundImage(); + + void slotOptionsAntialiasing(bool ); + void slotOptionsEmbedLogoExporting(bool toggle); + void slotOptionsProgressBarVisibility(bool toggle); + void slotOptionsToolbarVisibility(bool toggle); + void slotOptionsStatusBarVisibility(bool toggle); + void slotOptionsLeftPanelVisibility(bool toggle); + void slotOptionsRightPanelVisibility(bool toggle); + void slotOptionsDebugMessages(bool toggle); //HELP MENU - void slotTips(); + void slotHelpTips(); void slotHelp(); + void slotHelpCheckUpdates(); void slotHelpAbout(); void slotAboutQt(); + + //PUBLICLY AVAILABLE SLOTS. CALLED FROM GRAPHICSVIEW void nodeInfoStatusBar(Node*); void edgeInfoStatusBar (Edge*); - void openNodeContextMenu(); + void openEdgeContextMenu() ; - void windowInfoStatusBar(int, int); - void graphChanged(); - //Called by graphicswidget to update node coords in activeGraph - void updateNodeCoords(int no, int x, int y); + void updateNodeCoords(const int &nodeNumber, const int &x, const int &y); - //Called when user pushes the New Node button on the MW - void addNode(); - //Called by graphicswidget when the user middle-clicks - void addEdge (int v1, int v2, float weight); - //Called by graphicswidget when the user double-clicks - void addNodeWithMouse(int, QPointF); //Called by Graph on saving file. int is the network type saved. void networkSaved(int); @@ -350,6 +351,7 @@ public slots: void toolBoxAnalysisProminenceSelectChanged(int); void toolBoxAnalysisClusterabilitySelectChanged(int); void toolBoxLayoutByIndexButtonPressed(); + void toolBoxLayoutForceDirectedButtonPressed(); QList selectedNodes(); @@ -363,10 +365,10 @@ public slots: void addRelationToGraph(QString); private: - + QMap appSettings; QGraphicsScene *scene; - FilterEdgesByWeightDialog m_filterEdgesByWeightDialog; + FilterEdgesByWeightDialog m_DialogEdgeFilterByWeight; WebCrawlerDialog m_WebCrawlerDialog; NodeEditDialog *m_nodeEditDialog; @@ -374,6 +376,7 @@ public slots: RandErdosRenyiDialog *m_randErdosRenyiDialog; RandSmallWorldDialog *m_randSmallWorldDialog; RandScaleFreeDialog *m_randScaleFreeDialog; + SettingsDialog *m_settingsDialog; PreviewForm *previewForm; QList codecs; @@ -382,55 +385,67 @@ public slots: Graph activeGraph; QPrinter *printer; QToolBar *toolBar; - QComboBox *zoomCombo, *changeRelationCombo; - QTabWidget *toolBox; + + QGroupBox *leftPanel, *rightPanel ; + + QComboBox *editRelationChangeCombo; QProgressDialog *progressDialog; - Node *clickedJim; + Node *clickedNode; Edge *clickedEdge; QMenu *importSubMenu, *exportSubMenu, *editMenu, *statMenu, *helpMenu; QMenu *optionsMenu, *colorOptionsMenu, *edgeOptionsMenu, *nodeOptionsMenu, *viewOptionsMenu; QMenu *editNodeMenu, *editEdgeMenu, *centrlMenu, *layoutMenu; - QMenu *networkMenu, *randomNetworkMenu, *filterMenu; + QMenu *networkMenu, *randomNetworkMenu, *filterMenu, *recentFilesSubMenu; QMenu *randomLayoutMenu, *circleLayoutMenu, *levelLayoutMenu, *physicalLayoutMenu; QMenu *colorationMenu; - QCheckBox *layoutEadesBx, *layoutFruchtermanBx, *layoutKamandaBx, - *nodeSizesByOutDegreeBx,*nodeSizesByInDegreeBx, - *layoutGuidesBx; + QCheckBox *toolBoxNodeSizesByOutDegreeBx,*toolBoxNodeSizesByInDegreeBx, *toolBoxLayoutGuidesBx; QComboBox *toolBoxAnalysisGeodesicsSelect,*toolBoxAnalysisConnectivitySelect, *toolBoxAnalysisProminenceSelect, *toolBoxAnalysisClusterabilitySelect; QComboBox *toolBoxLayoutByIndexSelect, *toolBoxLayoutByIndexTypeSelect; + QComboBox *toolBoxLayoutForceDirectedSelect; - QPushButton *addNodeBt, *addEdgeBt, *removeNodeBt, *removeEdgeBt, - *toolBoxLayoutByIndexButton; + QPushButton *editNodeAddBt, *editEdgeAddBt, *removeNodeBt, *editEdgeRemoveBt; + QPushButton *toolBoxLayoutByIndexButton, *toolBoxLayoutForceDirectedButton; - QSpinBox *rotateSpinBox ; + QAction *zoomInAct,*zoomOutAct,*editRotateRightAct,*editRotateLeftAct, *editResetSlidersAct ; + QToolButton *zoomInBtn,*zoomOutBtn,*rotateLeftBtn,*rotateRightBtn, *resetSlidersBtn ; - QAction *fileNew, *fileOpen, *fileSave, *fileSaveAs,*fileClose, *printNetwork,*fileQuit; - QAction *exportBMP, *exportPNG, *exportPajek, *exportPDF, *exportDL, *exportGW, *exportSM, *exportList; - QAction *importPajek,*importSM, *importList, *importDot , *importDL, *importTwoModeSM; + QSlider *zoomSlider, *rotateSlider; - QAction *viewNetworkFileAct, *openTextEditorAct, *viewSociomatrixAct, *recreateDataSetAct; + QAction *networkNew, *networkOpen, *networkSave, *networkSaveAs, + *networkClose, *networkPrint,*networkQuit; + QAction *networkExportBMP, *networkExportPNG, *networkExportPajek, + *networkExportPDF, *networkExportDL, *networkExportGW, *networkExportSM, + *networkExportList; + QAction *networkImportPajek,*networkImportSM, *networkImportList, + *networkImportDot , *networkImportDL, *networkImportTwoModeSM; + QAction *networkViewFileAct, *openTextEditorAct, *networkViewSociomatrixAct, + *networkDataSetSelectAct; QAction *createErdosRenyiRandomNetworkAct, *createGaussianRandomNetworkAct; QAction *createLatticeNetworkAct, *createScaleFreeRandomNetworkAct; QAction *createSmallWorldRandomNetworkAct, *createRegularRandomNetworkAct; - QAction *displayNodeNumbersAct, *displayNodeLabelsAct, *displayNumbersInsideNodesAct; - QAction *selectNoneAct, *selectAllAct; - QAction *findNodeAct,*addNodeAct, *addEdgeAct, *removeNodeAct, *propertiesNodeAct, *removeEdgeAct; - QAction *changeNumbersSizeAct; - QAction *changeLabelsSizeAct, *changeAllNodesSizeAct, *changeAllNodesShapeAct; - QAction *changeEdgeLabelAct, *changeEdgeColorAct, *changeEdgeWeightAct; - QAction *filterNodesAct, *filterIsolateNodesAct, *filterEdgesAct, *transformNodes2EdgesAct, *symmetrizeAct; - QAction *changeBackColorAct, *changeAllNodesColorAct, *changeAllEdgesColorAct, *changeAllNumbersColorAct, - *changeAllLabelsColorAct; - QAction *drawEdgesWeightsAct, *displayEdgesWeightNumbersAct, *displayEdgesAct; - QAction *displayEdgesArrowsAct, *drawEdgesBezier,*considerEdgeWeightsAct; - QAction *backgroundImageAct, *viewToolBar, *viewStatusBar, *helpAboutApp, *helpAboutQt, *helpApp, *tipsApp; - QAction *antialiasingAct; + QAction *optionsNodeNumbersVisibilityAct, *optionsNodeLabelsVisibilityAct, *optionsNodeNumbersInsideAct; + QAction *editNodeSelectNoneAct, *editNodeSelectAllAct; + QAction *editNodeFindAct,*editNodeAddAct, *editNodeRemoveAct, *editNodePropertiesAct; + QAction *editEdgeAddAct, *editEdgeRemoveAct; + QAction *editNodeNumbersSizeAct, *editNodeLabelsSizeAct; + QAction *editNodeSizeAllAct, *editNodeShapeAll; + QAction *editEdgeLabelAct, *editEdgeColorAct, *editEdgeWeightAct; + QAction *filterNodesAct, *filterIsolateNodesAct, *filterEdgesAct; + QAction *transformNodes2EdgesAct, *editEdgeSymmetrizeAllAct, *editEdgeUndirectedAllAct; + QAction *changeBackColorAct, *editNodeColorAll, *editEdgeColorAllAct, + *editNodeNumbersColorAct,*editNodeLabelsColorAct; + QAction *optionsEdgeThicknessPerWeightAct, *optionsEdgeWeightNumbersAct, *optionsEdgesVisibilityAct; + QAction *optionsEdgeArrowsAct, *drawEdgesBezier,*considerEdgeWeightsAct; + QAction *optionsEdgeLabelsAct; + QAction *backgroundImageAct,*helpAboutApp, *helpAboutQt, *helpApp, *tipsApp; + QAction *helpCheckUpdatesApp; + QAction *openSettingsAct; QAction *webCrawlerAct; QAction *netDensity, *symmetryAct, *graphDistanceAct, *averGraphDistanceAct, @@ -440,7 +455,7 @@ public slots: QAction *cDegreeAct, *cInDegreeAct, *cClosenessAct, *cInfluenceRangeClosenessAct, *cBetweennessAct, *cInformationAct, *cPageRankAct, *cStressAct, *cPowerAct, *cEccentAct, *cProximityPrestigeAct; - QAction *randLayoutAct, *randCircleLayoutAct, *clearGuidesAct; + QAction *randLayoutAct, *randCircleLayoutAct, *layoutGuidesAct; QAction *layoutCircular_DC_Act, *layoutCircular_DP_Act, *layoutCircular_CC_Act, *layoutCircular_SC_Act, *layoutCircular_EC_Act, *layoutCircular_PC_Act, *layoutCircular_BC_Act, *layoutCircular_IC_Act, @@ -449,34 +464,35 @@ public slots: *layoutLevel_CC_Act, *layoutLevel_SC_Act, *layoutLevel_EC_Act, *layoutLevel_PC_Act, *layoutLevel_BC_Act, *layoutLevel_IC_Act, *layoutLevel_IRCC_Act,*layoutLevel_PRP_Act, *layoutLevel_PP_Act; - QAction *strongColorationAct, *regularColorationAct, *showProgressBarAct, *printDebugAct; + QAction *strongColorationAct, *regularColorationAct; QAction *springLayoutAct, *FRLayoutAct; QAction *nodeSizesByOutDegreeAct, *nodeSizesByInDegreeAct; - QAction *zoomInAct, *zoomOutAct ; - QAction *nextRelationAct, *prevRelationAct, *addRelationAct; - - QString fileName, networkName, previous_fileName; - QString dataDir, lastUsedDirPath; - QStringList fileNameNoPath, fortuneCookie, rgbValues; - QStringList tempFileNameNoPath, colorList, tips; - int statusBarDuration, minDuration, progressCounter; + QAction *editRelationNextAct, *editRelationPreviousAct, *editRelationAddAct; + enum { MaxRecentFiles = 5 }; + QAction *recentFileActs[MaxRecentFiles]; + + QString fileName, networkName, previous_fileName, progressMsg; + QString settingsFilePath, settingsDir ; + QStringList fileNameNoPath, fortuneCookie; + QStringList tempFileNameNoPath, tips, recentFiles; + int clickedNodeNumber; + int statusBarDuration, progressCounter; int maxNodes; - int initNodeSize, labelDistance, numberDistance,initNumberSize, initLabelSize; - int fortuneCookiesCounter, tipsCounter; + int fortuneCookiesCounter; //QString VERSION; bool pajekFileLoaded, adjacencyFileLoaded, dotFileLoaded, graphMLFileLoaded; - bool fileLoaded, checkSelectFileType; + bool fileLoaded; int fileFormat; bool networkModified; - bool bezier, edgeClicked, nodeClicked, markedNodesExist, showProgressBar, firstTime; + bool edgeClicked, nodeClicked, markedNodesExist, showProgressBar, firstTime; bool considerWeights, inverseWeights, askedAboutWeights; + float randomErdosEdgeProb; QString initFileCodec; - QString initEdgeColor, initNumberColor, initNodeShape, initLabelColor; QColor initBackgroundColor; QPointF cursorPosGW; //Carries the position of the cursor in graphicsWidget coordinates + QLabel *labelEdgesLCD, *networkLabel ; QLCDNumber *inDegreeLCD, *outDegreeLCD , *selectedNodeLCD, *clucofLCD; QLCDNumber *nodesLCD, *edgesLCD, *densityLCD; - QDateTime actualDateTime, actualDate, actualTime; QTime eTime; //used to time algorithms. diff --git a/manual/analysis.txt b/src/manual/analysis.txt similarity index 100% rename from manual/analysis.txt rename to src/manual/analysis.txt diff --git a/manual/bugs.txt b/src/manual/bugs.txt similarity index 100% rename from manual/bugs.txt rename to src/manual/bugs.txt diff --git a/manual/credits.txt b/src/manual/credits.txt similarity index 71% rename from manual/credits.txt rename to src/manual/credits.txt index b9a3fa99..92e3bd61 100644 --- a/manual/credits.txt +++ b/src/manual/credits.txt @@ -31,34 +31,34 @@ Many thanks to: - Martin Hohenberg - Victor Cardoso - Paul Johnson -- David de Ugarte, for an older Spanish translation \section References References -- Anthonisse, .I. M.(1971) The Rush in a Graph. Amsterdam: Mathematisch Centrum +- Anthonisse, .I. M.(1971). The Rush in a Graph. Amsterdam: Mathematisch Centrum - Brandes, U. (2001). A Faster Algorithm for Betweenness Centrality. Journal of Mathematical Sociology 25(2), pp.163-177. -- Brandes, U. (2001). Drawing on Physical Analogies.In M. Kaufmann and D. Wagner (Eds.): Drawing Graphs: Methods and Models. LNCS Tutorial 2025, pp. 71-86. -- Brin, S. and Page, L. (1998) The Anatomy of a Large-Scale Hypertextual Web Search Engine. In: Seventh International World-Wide Web Conference (WWW 1998), April 14-18, 1998, Brisbane, Australia. +- Brandes, U. (2001). Drawing on Physical Analogies. In M. Kaufmann and D. Wagner (Eds.): Drawing Graphs: Methods and Models. LNCS Tutorial 2025, pp. 71-86. +- Brin, S. and Page, L. (1998). The Anatomy of a Large-Scale Hypertextual Web Search Engine. In: Seventh International World-Wide Web Conference (WWW 1998), April 14-18, 1998, Brisbane, Australia. - Dasgupta S., Papadimitriou C.H. & Vazirani U.V. (2006). Algorithms. - Davis, J. A. & Leinhardt S. (1972). The Structure of Positive Relations in Small Groups.In J. Berger (Ed.), Sociological Theories in Progress , vol. 2. pp. 218-51. Boston, MA: Houghton Mifflin. - Eades, P, (1984). A Heuristic for Graph Drawing. Congressus Numerantuum, 42:149-160. - Erdos, P. and Renyi, A. (1959). On Random Graphs. I. Publicationes Mathematicae 6: 290-297. - Erdos, P. and Renyi, A. (1960). The Evolution of Random Graphs. Magyar Tud. Akad. Mat. Kutat Int. Kol. 5: 17-61. -- Freeman L. C. (1979). Centrality in Social Networks Conceptual Clarification. Social Networks, 1 (1978/79), pp. 215-239 -- Fruchterman, T.M.J. & Reingold, E.M. (1991). Graph Drawing by Force-Directed Placement. Software-Practice & Experience. Vol. 21, Is. 11, pp. 1129-1164. -- Gil, J. and Schmidt, S., (1996a). The origin of the Mexican network of power. In: International Social Network Conference, Charleston, SC, USA, pp. 22–25 -- Gil, J. and Schmidt, S., (1996b). The political network in Mexico. Social Networks 18, 355–381 +- Freeman L. C. (1979). Centrality in Social Networks Conceptual Clarification. Social Networks, 1 (1978/79), pp. 215-239 +- Fruchterman, T.M.J. & Reingold, E.M. (1991). Graph Drawing by Force-Directed Placement. Software-Practice & Experience. Vol. 21, Is. 11, pp. 1129-1164. +- Gil, J. & Schmidt, S., (1996a). The origin of the Mexican network of power. International Social Network Conference, Charleston, SC, USA, pp. 22–25 +- Gil, J. & Schmidt, S., (1996b). The political network in Mexico. Social Networks 18, 355–381 - Holland, P.W. & Leinhardt. S. (1970). A Method for Detecting Structure in Sociometric Data. American Journal of Sociology 70: 492-513. -- Holland, P.W. & S. Leinhardt. (1971). Transitivity in Structural Models of Small Groups. Comparative Group Studies 2:107-124. +- Holland, P.W. & S. Leinhardt. (1971). Transitivity in Structural Models of Small Groups. Comparative Group Studies 2:107-124. - Holland, P.W. & S. Leinhardt. (1975). Local Structure in Social Networks. Sociological Methodology<.em> 1976: 1-45. +- Kamada T. & Kawai S. (1989). An algorithm for drawing general undirected graphs. Information Processing Letters 31 (1989) 7-15. - Liu, C.L. (2000). Elements of Discrete Mathematics 2nd Edition. Greek Translation. -- Page L., Brin S., Motwani R., Winograd T. (1998). The PageRank Citation Ranking: Bringing Order to the Web +- Page L., Brin S., Motwani R., Winograd T. (1998). The PageRank Citation Ranking: Bringing Order to the Web. Stanford University. Technical Report. - Press W., Teukolsky S., Vetterling W. & Flannery B. (1992). Numerical Recipes in C, the art of scientific computing. - Sabidussi, G. (1966). The centrality index of a graph. Psychometrika 31, pp 581–603. -- Schank, T and Wagner. D (2005). Approximating Clustering Coefficient and Transitivity. J. Graph Algorithms Appl. 9(2): 265-275 -- Stephenson K. and Zelen M. (1989). Rethinking Centrality: Methods and examples. Social Networks 11 1-37. +- Schank, T & Wagner. D (2005). Approximating Clustering Coefficient and Transitivity. J. Graph Algorithms Appl. 9(2): 265-275 +- Stephenson K. & Zelen M. (1989). Rethinking Centrality: Methods and examples. Social Networks 11 1-37. - Stroustrup B. (1997). The C++ Programming Language. - Scott, J. (2000). Social Network Analysis, A handbook. - Qt Project (2014). Qt5: A cross-platform application and UI framework for developers using C++ or QML. https://qt-project.org @@ -82,4 +82,4 @@ For citing the SocNetv Manual, please use: Kalamaras D. (2015) The SocNetV Manual. Social Network Visualizer (SocNetV). http://socnetv.sourceforge.net -*/ \ No newline at end of file +*/ diff --git a/src/manual/footer.html b/src/manual/footer.html new file mode 100644 index 00000000..c8402f9a --- /dev/null +++ b/src/manual/footer.html @@ -0,0 +1,21 @@ + + + +

+ + + + + + diff --git a/manual/formats.txt b/src/manual/formats.txt similarity index 100% rename from manual/formats.txt rename to src/manual/formats.txt diff --git a/manual/generate.txt b/src/manual/generate.txt similarity index 100% rename from manual/generate.txt rename to src/manual/generate.txt diff --git a/manual/gfdl.txt b/src/manual/gfdl.txt similarity index 100% rename from manual/gfdl.txt rename to src/manual/gfdl.txt diff --git a/manual/gui.txt b/src/manual/gui.txt similarity index 80% rename from manual/gui.txt rename to src/manual/gui.txt index 650f09d5..a0b88b78 100644 --- a/manual/gui.txt +++ b/src/manual/gui.txt @@ -7,13 +7,13 @@ SocNetV has a simple Graphical User Interface (GUI) composed of: - a \ref themenu [menu bar] - a \ref toolbar toolbar -- a \ref dock dock -- a \ref canvas canvas +- a \ref sidebars side panels +- a \ref canvas main canvas - a statusbar -![SocNetV Main Window](./manual/socnetv-main-window-annotated.png) +![SocNetV Main Window](./src/manual/socnetv-main-window-annotated.png) \section themenu The menu @@ -33,22 +33,23 @@ organized in 6 menus: \section toolbar The toolbar Below the menu, the toolbar provides the usual icons: new network creation, -load a network, save, zoom in-out, rotate, switch between relations (or add a new one) -and display help messages for the menu options. +load a network, save, and print as well switching between relations +(or add a new one) and display help messages for the menu options. -The middle part of the window is occupied by the dock/toolbar (left-side) +The main part of the application window is occupied by the sidebar panels (left-right) and a virtual "canvas" (right-side) where network nodes and edges appear. -\section dock The dock/toolbox +\section sidebars The Panels -The toolbox, on the left of the window, has two tabs: Controls and Statistics. +The panel on the left of the window is the Control Panel. +The panel on the right is the Statistics Panel. -\subsection dockControls Controls tab +\subsection panelControls Control Panel -At the top of the Controls tab there are 4 buttons to edit the network (add/remove node, add/remove edge). +At the top of the Control Panel there are 4 buttons to edit the network (add/remove node, add/remove edge). Below them, there are two groups of options to Analyze and Visualize the loaded network. @@ -59,32 +60,34 @@ In the Analyze group, options are categorized in four submenus: - Clusterability: Click to compute cliques, triad census etc. - Prominence: This menu allows you to select and compute one of the many Centrality and Prestige indices that SocNetV supports. -When you select an option, SocNetV computes what you asked and displays the report in a new window. +When you select an option, SocNetV computes what you asked and displays the report in a new texteditor window. \note All reports are automatically saved in a directory called "socnetv-data" in your HOME folder. Of course, you can edit the report as you wish and save it to another filename. -![SocNetV Analysis](./manual/socnetv-analysis.jpg) +![SocNetV Analysis](./src/manual/socnetv-analysis.jpg) -In the Visualize group, there are menus and checkboxes to apply visualization -layouts to the current network. +In the Visualize group, there are menus and checkboxes to embed visualization layouts to the current network. -With one click, SocNetV can visualize the network in intuitive ways: +With one click, SocNetV can visualize the network in some intuitive ways. There are two layout categories: - By prominence indices. Here you can select a prominence metric (i.e. Betweenness) and a layout type (i.e. circular). Hit "Apply" and voila! -- By dynamic models (i.e. Force directed) +- By dynamic models (i.e. Force directed), such as the Eades model. Finally, at the end of the toolbox there are options to toggle node sizes according to their inDegree/outDegree and enable/disable layout guidelines. -\subsection dockStatistics Statistics tab +\subsection panelStatistics Statistics Panel -The Statistics tab is mainly occupied by informative LCDs. +The Statistics Panel is mainly occupied by informative LCDs. -These display statistics for the active network (i.e. node and edges counters, density, counters of inLinked/outLinked nodes, etc) as well as the selected node (its number, in-Links and out-Links). +At the top of the Panel there is a Network Type label, which indicates whether your data is directed or undirected. +The LCDs below display statistics for the active network (i.e. node and edge counts, density, counts of inLinked/outLinked nodes, etc). +Furthermore, under "Active Node" there are LCDs which refer to the last clicked node (notably its number, in-Degree, out-Degree and Clustering Coefficient). -![Main Window annotated](./manual/socnetv-main-window-annotated-2.png) + +![Main Window annotated](./src/manual/socnetv-main-window-annotated-2.png) \section canvas The canvas @@ -111,14 +114,14 @@ SocNetV enables you to create networks by point and clicking on the canvas or lo There are multiple ways to create or edit nodes and links in SocNetV: - from the menus -- from the dock buttons, or -- by right/left/middle-clicking on the canvas. +- from the left panels buttons, or +- by right/left/middle/double-clicking on the canvas. \subsection NodeCreate Creating and handling nodes -To create a new node, you can double-click on the canvas or click on the "Add node" button. +To create a new node, you can double-click on the canvas, click on the "Add node" button or press CTRL+. You can move a node by left-clicking on it and dragging it with mouse. @@ -142,11 +145,17 @@ If you want to select more than one node, press and hold down the left mouse but \subsection LinkCreate Creating and editing edges -To create a new directed edge, middle-click on the source node and then middle-click again on the target node. By default, all new links created this way have weight 1. +There are lots of ways to create edges in SocNetV. + +For instance, you can do it by middle-clicking or double-clicking on a source node and then middle-clicking or double-clicking again on a target node. + +By default, all new links created this way have a unit weight (w=1). + +You can also create edges by right-clicking on any node (thus selected as source), and selecting "Create Edge". In the new dialog, just enter the target node number and the desired edge weight. -If your mouse doesn't have middle button (did you try pressing the mouse wheel?), or you find it difficult, you can right-click on the source node, then select "Create Edge". +Finally, you can click on the "Add edge" button from the left Control Panel. In that case, you will be asked for both the source and the target node numbers (and the edge weight). -In the dialog, just enter the target node number and the desired edg weight. Alternatively, you can click on the "Add edge" button from the dock. In that case, you will be asked for both the source and the target node numbers (and the edge weight). +If you prefer using the keyboard, you can also create new edges using the keyboard shortcut CTRL+/. You will be asked for source and target nodes and their weight. \note When you create the first edge of a network, you will be asked to label the current \ref Relations relationship. @@ -258,4 +267,4 @@ Except printing, you can export your work into raster (BMP and PNG) images, as w -*/ \ No newline at end of file +*/ diff --git a/src/manual/header.html b/src/manual/header.html new file mode 100644 index 00000000..bb88260b --- /dev/null +++ b/src/manual/header.html @@ -0,0 +1,66 @@ + + + + + + + +$projectname: $title +$title + + + + + + + + + + + + + + +$treeview +$search +$mathjax + +$extrastylesheet + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + +
+
$projectname +  $projectnumber +
+
$projectbrief
+
+
$projectbrief
+
$searchbox
+
+ + diff --git a/manual/intro.txt b/src/manual/intro.txt similarity index 100% rename from manual/intro.txt rename to src/manual/intro.txt diff --git a/manual/manual.txt b/src/manual/manual.txt similarity index 100% rename from manual/manual.txt rename to src/manual/manual.txt diff --git a/manual/mathjaxconfig.js b/src/manual/mathjaxconfig.js similarity index 100% rename from manual/mathjaxconfig.js rename to src/manual/mathjaxconfig.js diff --git a/src/manual/socnetv-analysis.jpg b/src/manual/socnetv-analysis.jpg new file mode 100644 index 00000000..9f5d32c7 Binary files /dev/null and b/src/manual/socnetv-analysis.jpg differ diff --git a/manual/socnetv-logo-manual.png b/src/manual/socnetv-logo-manual.png similarity index 100% rename from manual/socnetv-logo-manual.png rename to src/manual/socnetv-logo-manual.png diff --git a/src/manual/socnetv-main-window-annotated-2.png b/src/manual/socnetv-main-window-annotated-2.png new file mode 100644 index 00000000..f83c7b7a Binary files /dev/null and b/src/manual/socnetv-main-window-annotated-2.png differ diff --git a/src/manual/socnetv-main-window-annotated.png b/src/manual/socnetv-main-window-annotated.png new file mode 100644 index 00000000..92088d45 Binary files /dev/null and b/src/manual/socnetv-main-window-annotated.png differ diff --git a/src/manual/socnetv.css b/src/manual/socnetv.css new file mode 100644 index 00000000..657ade88 --- /dev/null +++ b/src/manual/socnetv.css @@ -0,0 +1,3 @@ +.contents .image img { width: 90%; } +.contents h1 { margin-top: 30px; } +.contents h2 { margin-top: 15px; } diff --git a/manual/visualisation.txt b/src/manual/visualisation.txt similarity index 76% rename from manual/visualisation.txt rename to src/manual/visualisation.txt index 0794ef48..d175f6ab 100644 --- a/manual/visualisation.txt +++ b/src/manual/visualisation.txt @@ -58,38 +58,33 @@ let go so that the spring forces on the rings move the system to a minimal energy state." -In our implementation, nodes are regarded as physical bodies (i.e. rings) which exert -repelling forces to each other, while edges become springs which excert attractive forces. +In our implementation, every node \f$ u \in V \f$ of the network is regarded as a +physical body (i.e. ring) which exert repelling force \f$ F_{r} \f$ to every other node. +At the same time, every edge \f$(u,v) \in E \f$ becomes a "spring" which excert +attractive force \f$ F_{a} \f$ between the nodes \f$u\f$ and \f$v\f$ it connects. +Following Eades, the forces of springs do now follow Hooke'w Law. +Instead we assume weaker, logarithmic forces between edges \f$(u,v) \in E \f$: -These forces are applied to the nodes iteratively, pulling them closer together or pushing them further apart, -until the system comes to an equilibrium state (node positions do not change anymore). +\f[ F_{a}^{u,v} = c_1 \cdot \log{ \frac{d_{u,v}}{c_2} } \f] +where \f$d\f$ the euclidean distance, the constant \f$ c_1 = 2 \f$ and the other constant \f$ c_2 \f$ is the "natural length" of the spring which is a function of screen/viewport area and the width of the vertex: -Note that, following Eades, the forces of springs do now follow Hooke'w Law. -Instead we assume weaker logarithmic forces between pair of vertices v and u: +\f$ c_2 = vertexWidth + \sqrt{ \frac { screenArea } { |V| } } \f$ -~~~~~ -AttractiveForce= c_spring * log10 ( distance(v,u) / naturalLength ) -~~~~~ +The repelling force \f$ F_{r} \f$ between every pair of nodes is computed with the formula: -~~~~~ -RepellingForce = c_rep / (distance(v,u) * distance(v,u) ); -~~~~~ +\f[ F_{r} = \frac { c_3 } { d_{u,v} ^2 } \f] -where +where \f$ c_3=1 \f$ -~~~~~ -naturalLength= vertexWidth + Sqrt( screenArea / |Vertices| ) -c_spring=2 -c_rep=1; -~~~~~ +These forces are applied to the nodes iteratively, pulling them closer together or pushing them further apart, +until the system comes to an equilibrium state (node positions do not change anymore). -Note: Repulsive forces are calculated between every pair of -vertices, but attractive forces are calculated only between neighbours. +Note: Repulsive forces are calculated between every pair of vertices, but attractive forces are calculated only between neighbours (nodes connected by an edge/arc). \subsection LayoutFR Fruchterman-Reingold @@ -133,4 +128,4 @@ optimalDistance= sqrt ( screenArea / |Vertices| ) Following Fruchterman and Reingold, for every vertex v we compute repulsive forces only for vertices within a circular area of radius 2*optimalDistance from v. -*/ \ No newline at end of file +*/ diff --git a/src/matrix.cpp b/src/matrix.cpp index d2cfe2ac..ffe8d652 100755 --- a/src/matrix.cpp +++ b/src/matrix.cpp @@ -5,7 +5,7 @@ matrix - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -31,8 +31,9 @@ #define TINY 1.0e-20 #include //allows the use of RAND_MAX macro +#include #include //needed for fabs, qFloor etc - +#include /** @@ -44,7 +45,7 @@ Matrix::Matrix (int rowDim, int colDim) : m_rows (rowDim), m_cols(colDim) { row = new (nothrow) Row[ m_rows ]; Q_CHECK_PTR( row ); - for (register int i=0;i 99999) @@ -212,7 +220,7 @@ QTextStream& operator << (QTextStream& os, Matrix& m){ os< 99999) newFieldWidth = fieldWidth -6; else if ( r > 9999) @@ -228,7 +236,7 @@ QTextStream& operator << (QTextStream& os, Matrix& m){ os << qSetFieldWidth(1) << QString("-"); os.setPadChar(' '); os< 99999) newFieldWidth = fieldWidth -5; @@ -243,7 +251,7 @@ QTextStream& operator << (QTextStream& os, Matrix& m){ else newFieldWidth = fieldWidth; os << qSetFieldWidth(newFieldWidth) << right << QString("%1 |").arg(actorNumber) ; - for (register int c = 0; c < m.cols(); ++c) { + for (int c = 0; c < m.cols(); ++c) { element = m(r,c) ; newFieldWidth = fieldWidth; if ( element == RAND_MAX ) @@ -281,7 +289,7 @@ QTextStream& operator << (QTextStream& os, Matrix& m){ else newFieldWidth = fieldWidth; if ( element == -1 || element == RAND_MAX) // we print infinity symbol instead of -1 (distances matrix). - os << qSetFieldWidth(newFieldWidth) << right << QString("\xE2\x88\x9E"); + os << qSetFieldWidth(newFieldWidth) << right << infinity; else os << qSetFieldWidth(newFieldWidth) << right << element; @@ -295,8 +303,8 @@ QTextStream& operator << (QTextStream& os, Matrix& m){ void Matrix::findMinMaxValues (float & maxVal, float &minVal){ maxVal=0; minVal=RAND_MAX; - for (register int r = 0; r < rows(); ++r) { - for (register int c = 0; c < cols(); ++c) { + for (int r = 0; r < rows(); ++r) { + for (int c = 0; c < cols(); ++c) { if ( item(r,c) > maxVal) maxVal = item(r,c) ; if ( item(r,c) < minVal){ @@ -365,7 +373,7 @@ int Matrix::edgesFrom(int r){ int Matrix::edgesTo(const int t){ int m_inEdges=0; - for (register int i = 0; i < rows(); ++i) { + for (int i = 0; i < rows(); ++i) { if ( item(i, t) != 0 ) m_inEdges++; } @@ -376,7 +384,7 @@ int Matrix::edgesTo(const int t){ int Matrix::totalEdges(){ int m_totalEdges=0; - for (register int r = 0; r < rows(); ++r) { + for (int r = 0; r < rows(); ++r) { m_totalEdges+=edgesFrom(r); } qDebug() << "Matrix: totalEdges " << m_totalEdges; @@ -386,8 +394,8 @@ int Matrix::totalEdges(){ bool Matrix::printMatrixConsole(){ qDebug() << "Matrix: printMatrixConsole"; - for (register int r = 0; r < rows(); ++r) { - for (register int c = 0; c < cols(); ++c) + for (int r = 0; r < rows(); ++r) { + for (int c = 0; c < cols(); ++c) QTextStream(stdout) << item(r,c) <<' '; QTextStream(stdout) <<'\n'; } @@ -402,8 +410,8 @@ void Matrix::deleteRowColumn(int erased){ --m_rows; qDebug() << "Matrix: m_rows now " << m_rows << ". Resizing..."; - for (register int i=0;i=j) continue; - for (register int k=0;k j ) { if (a.item(i,k)!=0 && b.item(j,k)!=0) setItem(i,j, item(i,j)+a.item(i,k)*b.item(j,k)); @@ -499,7 +507,7 @@ Matrix& Matrix::productSym( Matrix &a, Matrix & b) { Matrix& Matrix::pow (int power, bool symmetry) { Matrix t=*this; - for (register int k=1; k qFabs ( m_pivot ) ) { qDebug() << " A("<< i+1 << ","<< j+1 << ") = " << temp_pivot @@ -600,7 +608,7 @@ Matrix& Matrix::inverseByGaussJordanElimination(Matrix &A){ qDebug()<<" multiplyRow() "<< j+1 << " by value " << 1/m_pivot ; - for ( register int k=0; k< rows(); k++) { + for ( int k=0; k< rows(); k++) { A.setItem ( j, k, (1/m_pivot) * A.item (j, k) ); setItem ( j, k, (1/m_pivot) * item (j, k) ); qDebug()<<" A.item("<< j+1 << ","<< k+1 << ") = " << A.item(j,k); @@ -608,7 +616,7 @@ Matrix& Matrix::inverseByGaussJordanElimination(Matrix &A){ } qDebug() << "eliminate variables FromRowsBelow()" << j+1 ; - for ( register int i=0; i< rows(); i++) { + for ( int i=0; i< rows(); i++) { qDebug()<<" Eliminating item("<< i+1 << ","<< j+1 << ") = " << A.item(i,j) << " while at column j="< //used for qDebug function -#include -#include +#include + + #include // std::pair, std::make_pair using namespace std; //or else compiler groans for nothrow +class QTextStream; + class Row { public: Row (int cols=0) { cell=new (nothrow) float [m_cols=cols]; Q_CHECK_PTR( cell ); - for (register int i=0;i #include #include -#include //for QT_VERSION +#include #include #include "graphicswidget.h" #include "edge.h" #include "nodelabel.h" #include "nodenumber.h" -#include //sqrt +#include -Node::Node( GraphicsWidget* gw, int num, int size, - QString col, QString shape, bool numIn, - int ldist, int ndist, QPointF p - ) : graphicsWidget (gw) + + +Node::Node(GraphicsWidget* gw, const int &num, const int &size, + const QString &color, const QString &shape, + const bool &showNumbers, const bool &numbersInside, + const QString &numberColor, const int &numberSize, + const int &numDistance, + const bool &showLabels, const QString &label, const QString &labelColor, + const int &labelSize, const int &labelDistance, + QPointF p + ) : graphicsWidget (gw) { - Q_UNUSED(p); - graphicsWidget->scene()->addItem(this); //Without this nodes don't appear on the screen... - -//ItemSendsGeometryChanges introduced in Qt 4.6... -#if QT_VERSION >= 0x040600 - setFlags(ItemSendsGeometryChanges | ItemIsSelectable | ItemIsMovable); - setCacheMode(QGraphicsItem::ItemCoordinateCache); //QT < 4.6 if a cache mode is set, nodes do not respond to hover events -//DeviceCoordinateCache -#else - setFlags(ItemIsSelectable | ItemIsMovable ); //Without this, the node cannot move nor be selected ... - setCacheMode(QGraphicsItem::NoCache); //QT < 4.6 if a cache mode is set, nodes do not respond to hover events -#endif + graphicsWidget->scene()->addItem(this); //Without this nodes don't appear on the screen... + + setFlags(ItemSendsGeometryChanges | ItemIsSelectable | ItemIsMovable ); + //setCacheMode(QGraphicsItem::ItemCoordinateCache); //QT < 4.6 if a cache mode is set, nodes do not respond to hover events + + setCacheMode(QGraphicsItem::NoCache); //QT < 4.6 if a cache mode is set, nodes do not respond to hover events setAcceptHoverEvents(true); - m_num=num; - m_size=size; - m_hasLabel=false; - m_hasNumber=false; - m_isNumberInside = numIn; - m_shape=shape; - m_col_str=col; - m_col=QColor(col); - m_nd=ndist; - m_ld=ldist; - m_poly_t=new QPolygon(3); - m_poly_d=new QPolygon(4); - qDebug()<< "Node: constructor: initial position at: " - << this->x()<<", "<y() - << " Will move at: "<< p.x()<<", "<x()<<", "<y(); } /** - Used by MW::slotChangeNodeColor + Used by MW::slotChangeNodeColor */ void Node::setColor(QString str) { - prepareGeometryChange(); - m_col=QColor(str); + prepareGeometryChange(); + m_col=QColor(str); update(); } /** - Used by MW::slotFindNode() + Used by MW::slotEditNodeFind() */ void Node::setColor(QColor color){ prepareGeometryChange(); - m_col=color; + m_col=color; m_col_str = m_col.name(); update(); } QString Node::color() { - return m_col_str; + return m_col_str; } /** Sets the size of the node */ -void Node::setSize(int size){ - qDebug("Node: setSize()"); - prepareGeometryChange(); - m_size=size; - foreach (Edge *edge, inEdgeList) { - qDebug("Node: updating edges in inEdgeList"); - edge->setEndOffset(size); - } - foreach (Edge *edge, outEdgeList) { - qDebug("Node: updating edges in outEdgeList"); - edge->setStartOffset(size); - } - setShape(m_shape); +void Node::setSize(const int &size){ + qDebug("Node: setSize()"); + prepareGeometryChange(); + m_size=size; + foreach (Edge *edge, inEdgeList) { + qDebug("Node: updating edges in inEdgeList"); + edge->setEndOffset(size); + } + foreach (Edge *edge, outEdgeList) { + qDebug("Node: updating edges in outEdgeList"); + edge->setStartOffset(size); + } + setShape(m_shape); } /** Used by MainWindow::findNode() and Edge::Edge() */ -int Node::size(){ - qDebug("size()"); - return m_size; +int Node::size() const{ + qDebug("size()"); + return m_size; } /** Called every time the user needs to change the shape of an node. */ void Node::setShape(const QString shape) { - qDebug("Node: setShape()"); - prepareGeometryChange(); - m_shape=shape; - qDebug ("Node: setShape(): node is at x=%f and y=%f", x(), y()); + qDebug("Node: setShape()"); + prepareGeometryChange(); + m_shape=shape; + qDebug ("Node: setShape(): node is at x=%f and y=%f", x(), y()); + + m_path = new QPainterPath; + if ( m_shape == "circle") { + m_path->addEllipse (-m_size, -m_size, 2*m_size, 2*m_size); + } + else if ( m_shape == "ellipse") { + m_path->addEllipse(-m_size, -m_size, 2*m_size, 1.7* m_size); + } + else if ( m_shape == "box" || m_shape == "rectangle" ) { //rectangle: for GraphML compliance + m_path->addRect (-m_size , -m_size , 1.8*m_size , 1.8*m_size ); + } + else if (m_shape == "roundrectangle" ) { //roundrectangle: GraphML only + m_path->addRoundedRect (-m_size , -m_size , 1.8*m_size , 1.8*m_size, 60.0, 60.0, Qt::RelativeSize ); + } + else if ( m_shape == "triangle") { + m_path->moveTo(-m_size,0.95* m_size) ; + m_path->lineTo(m_size,0.95*m_size); + m_path->lineTo( 0,-1*m_size); + m_path->lineTo(-m_size,0.95*m_size) ; + m_path->closeSubpath(); + } + else if ( m_shape == "star") { + m_path->setFillRule(Qt::WindingFill); + m_path->moveTo(-0.8*m_size,0.6* m_size) ; + m_path->lineTo(+0.8*m_size,0.6*m_size); + m_path->lineTo( 0,-1*m_size); + m_path->lineTo(-0.8*m_size,0.6*m_size) ; + m_path->closeSubpath(); + + m_path->moveTo(0, 1* m_size) ; + m_path->lineTo(+0.8*m_size,-0.6*m_size); + m_path->lineTo(-0.8*m_size,-0.6*m_size) ; + m_path->lineTo(0, 1* m_size); + m_path->closeSubpath(); + } + else if ( m_shape == "diamond"){ + m_path->moveTo(-m_size, 0); + m_path->lineTo( 0,-1*m_size); + m_path->lineTo( m_size, 0); + m_path->lineTo( 0, 1*m_size); + m_path->lineTo(-m_size, 0) ; + m_path->closeSubpath(); + } update(); } @@ -144,8 +206,8 @@ void Node::setShape(const QString shape) { * Used by the collision algorithm in collidesWithItem() */ QPainterPath Node::shape() const { - //qDebug ("Node: shape()"); - return (*m_path); + //qDebug ("Node: shape()"); + return (*m_path); } @@ -154,121 +216,92 @@ QPainterPath Node::shape() const { * That is the rectangle where all painting will take place. */ QRectF Node::boundingRect() const { - qreal adjust = 6; - return QRectF(-m_size -adjust , -m_size-adjust , 2*m_size+adjust , 2*m_size +adjust); - - + qreal adjust = 5; + return QRectF(-m_size -adjust , -m_size-adjust , 2*m_size+adjust , 2*m_size +adjust); } /** - Does the actual painting. - Called by GraphicsView in every update() + */ +/** + * @brief Node::paint + * Does the actual painting using the QPainterPath created by the setShape() + * Called by GraphicsView and Node methods in every update() + * @param painter + * @param option + */ void Node::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) { -// painter->setClipRect( option->exposedRect ); + // painter->setClipRect( option->exposedRect ); //if the node is being dragged around, darken it! - if (option->state & QStyle::State_Selected) { - //qDebug()<< " node : selected "; - painter->setBrush(m_col.dark(150)); - } - else if (option->state & QStyle::State_MouseOver) { - //qDebug()<< " node : mouse over"; - painter->setBrush(m_col.dark(150)); - setZValue(255); - } - //else if (option->state & QStyle::State_Sunken) { - //qDebug()<< " node : sunken "; - //setZValue(255); - //painter->setBrush(m_col_dark.dark(160)); - //} - else { //no, just paint it with the usual color. - //qDebug()<< " node : nothing"; - setZValue(254); - painter->setBrush(m_col); - } - painter->setPen(QPen(Qt::black, 0)); - - m_path = new QPainterPath; - if ( m_shape == "circle") { - m_path->addEllipse (-m_size, -m_size, 2*m_size, 2*m_size); - } - else if ( m_shape == "ellipse") { - m_path->addEllipse(-m_size, -m_size, 2*m_size, 1.5* m_size); - } - else if ( m_shape == "box" || m_shape == "rectangle" ) { //rectangle: for GraphML compliance - m_path->addRect (-m_size , -m_size , 1.8*m_size , 1.8*m_size ); - } - else if (m_shape == "roundrectangle" ) { //roundrectangle: GraphML only - m_path->addRoundedRect (-m_size , -m_size , 1.8*m_size , 1.8*m_size, 60.0, 60.0, Qt::RelativeSize ); - } - else if ( m_shape == "triangle") { - m_poly_t -> setPoints (3, 0,-m_size, -m_size,m_size, m_size,+m_size); - m_path->addPolygon(*m_poly_t); - m_path->closeSubpath(); - } - else if ( m_shape == "diamond"){ - m_poly_d -> setPoints (4, 0,-m_size, -m_size,0, 0,+m_size, +m_size,0); - m_path->addPolygon(*m_poly_d); - m_path->closeSubpath(); - } - - painter->drawPath (*m_path); -} - - + if (option->state & QStyle::State_Selected) { + //qDebug()<< " node : selected "; + painter->setBrush(m_col.dark(150)); + } + else if (option->state & QStyle::State_MouseOver) { + //qDebug()<< " node : mouse over"; + painter->setBrush(m_col.dark(150)); + setZValue(255); + } + //else if (option->state & QStyle::State_Sunken) { + //qDebug()<< " node : sunken "; + //setZValue(255); + //painter->setBrush(m_col_dark.dark(160)); + //} + else { //no, just paint it with the usual color. + //qDebug()<< " node : nothing"; + setZValue(254); + painter->setBrush(m_col); + } + painter->setPen(QPen(QColor("#222"), 0)); + painter->drawPath (*m_path); -void Node::setLabelText ( QString label) { - prepareGeometryChange(); - m_label->setPlainText(label); - m_hasLabel=true; -} - + if (m_hasNumberInside && m_hasNumber) { + // m_path->setFillRule(Qt::WindingFill); + painter->setPen(QPen(QColor(m_numColor), 0)); + if (m_num > 999) { + painter->setFont(QFont("Times", (m_numSize)? m_numSize-1: 0.66*m_size, QFont::Normal)); + painter->drawText(-0.8*m_size,m_size/3, QString::number(m_num) ); + } + else if (m_num > 99) { + painter->setFont(QFont("Times", (m_numSize)? m_numSize-1: 0.66*m_size, QFont::Normal)); + painter->drawText(-0.6 * m_size,m_size/3, QString::number(m_num) ); + } + else if (m_num > 9 ) { + painter->setFont(QFont("Times", (m_numSize)? m_numSize: 0.66*m_size, QFont::Normal)); + painter->drawText(-0.5*m_size,m_size/3,QString::number(m_num) ); + } + else { + painter->setFont(QFont("Times", (m_numSize)? m_numSize: 0.66*m_size, QFont::Normal)); + painter->drawText(-0.33*m_size,m_size/3,QString::number(m_num) ); + } + } -QString Node::labelText ( ) { - if (m_hasLabel) { - return m_label->toPlainText(); - } - else return ""; } -void Node::setNumberInside (bool numIn){ - - m_isNumberInside = numIn; - - //Move its graphic number - QPointF myPos = this->pos(); - if ( m_hasNumber ) - { - if (!m_isNumberInside) { //move it outside - m_number -> setZValue(254); - m_number -> setPos( myPos.x()+m_nd, myPos.y() ); - } - else { //move it inside node - this->setSize(m_size+2); //increase size to display nicely the number - m_number -> setZValue(255); - m_number->setPos( myPos.x() - m_size-2, myPos.y() - m_size-2 ); - } - } -} - -/** - * Propagates the changes to connected elements, i.e. edges, numbers, etc. +/** + * @brief Node::itemChange + * Called when the node moves or becomes disabled or changes its visibility + * Propagates the changes to connected elements, i.e. edges, numbers, etc. * Checks if the node is inside the scene. + * @param change + * @param value + * @return */ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) { - QPointF newPos = value.toPointF(); + QPointF newPos = value.toPointF(); switch (change) { case ItemPositionHasChanged : { + //setCacheMode( QGraphicsItem::ItemCoordinateCache ); foreach (Edge *edge, inEdgeList) //Move each inEdge of this node edge->adjust(); foreach (Edge *edge, outEdgeList) //Move each outEdge of this node @@ -276,17 +309,13 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) { //Move its graphic number if ( m_hasNumber ) { - if (!m_isNumberInside) { //move it outside + if (!m_hasNumberInside) { //move it outside m_number -> setZValue(254); - m_number -> setPos( m_size+m_nd, 0); - } - else { //move it inside node - m_number -> setZValue(255); - m_number -> setPos( - m_size, - m_size-3); + m_number -> setPos( m_size+m_numberDistance, 0); } } if (m_hasLabel) { - m_label->setPos( -2, m_ld+m_size); + m_label->setPos( -m_size, m_labelDistance+m_size); } if ( newPos.x() !=0 && newPos.y() != 0 ){ graphicsWidget->nodeMoved(nodeNumber(), (int) newPos.x(), (int) newPos.y()); @@ -323,132 +352,319 @@ QVariant Node::itemChange(GraphicsItemChange change, const QVariant &value) { /** handles the events of a click on a node */ -void Node::mousePressEvent(QGraphicsSceneMouseEvent *event) { - qDebug() << "Node::mousePressEvent() " - << " set selected and emitting nodeClicked"; - this->setSelected(true); -// emit nodeClicked(this); - graphicsWidget->nodeClicked(this); - if ( event->button()==Qt::LeftButton ) { - qDebug("Node::mousePressEvent() left click "); - - } - if ( event->button()==Qt::RightButton ) { - qDebug("Node: Right-click on node, at %i, %i", event->screenPos().x(), event->screenPos().y()); -// emit openNodeContextMenu(); - graphicsWidget->openNodeContextMenu(); - /** Update commented out - caused segmentation fault when removing node */ -// update(); -// QGraphicsItem::mousePressEvent(event); - } - if ( event->button()==Qt::MidButton) { - qDebug("Node: Middle-Click on a node. Calling GraphicsWidget startEdge()"); -// emit startEdge(this); - graphicsWidget->startEdge(this); - } - +void Node::mousePressEvent(QGraphicsSceneMouseEvent *event) { + QGraphicsItem::mousePressEvent(event); } void Node::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - update(); - QGraphicsItem::mouseReleaseEvent(event); + update(); + QGraphicsItem::mouseReleaseEvent(event); } +/** + * @brief Node::hoverEnterEvent + * on hover on node, it highlights all connected edges + * @param event + */ +void Node::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { + foreach (Edge *edge, inEdgeList) + edge->highlight(true); + foreach (Edge *edge, outEdgeList) + edge->highlight(true); + QGraphicsItem::hoverEnterEvent(event); +} + +/** + * @brief Node::hoverLeaveEvent + * Stops the connected edges highlighting + * @param event + */ +void Node::hoverLeaveEvent(QGraphicsSceneHoverEvent *event){ + foreach (Edge *edge, inEdgeList) + edge->highlight(false); + foreach (Edge *edge, outEdgeList) + edge->highlight(false); + QGraphicsItem::hoverLeaveEvent(event); +} +/** + * @brief Node::addInLink + * Called from a new connected in-link to acknowloedge itself to this node. + * @param edge + */ void Node::addInLink( Edge *edge ) { - qDebug() << "Node: addInLink() for "<< m_num; - inEdgeList.push_back( edge); - //qDebug ("Node: %i inEdgeList has now %i edges", m_num, inEdgeList.size()); + qDebug() << "Node: addInLink() for "<< m_num; + inEdgeList.push_back( edge); + //qDebug ("Node: %i inEdgeList has now %i edges", m_num, inEdgeList.size()); } void Node::deleteInLink( Edge *link ){ - qDebug () << "Node: deleteInLink for "<< m_num; - //qDebug ("Node: %i inEdgeList has %i edges", m_num, inEdgeList.size()); - inEdgeList.remove( link); - //qDebug ("Node: %i inEdgeList has now %i edges", m_num, inEdgeList.size()); + qDebug () << "Node::deleteInLink() - to " << m_num + << " inEdgeList size: " << inEdgeList.size(); + inEdgeList.remove( link ); + qDebug () << "Node::deleteInLink() - deleted to " << m_num + << " inEdgeList size: " << inEdgeList.size(); } void Node::addOutLink( Edge *edge ) { - qDebug("Node: addOutLink()"); - outEdgeList.push_back( edge); -// qDebug ("Node: outEdgeList has now %i edges", outEdgeList.size()); + qDebug("Node: addOutLink()"); + outEdgeList.push_back( edge); + // qDebug ("Node: outEdgeList has now %i edges", outEdgeList.size()); } void Node::deleteOutLink(Edge *link){ - qDebug () << "Node: deleteOutLink() from " << m_num; -// qDebug ("Node: %i outEdgeList has %i edges", m_num, outEdgeList.size()); + qDebug () << "Node::deleteOutLink() - from " << m_num + << " outEdgeList size: " << outEdgeList.size(); outEdgeList.remove( link); -// qDebug ("Node: %i outEdgeList has now %i edges", m_num, outEdgeList.size()); + qDebug () << "Node::deleteOutLink() - deleted from " << m_num + << " outEdgeList size now: " << outEdgeList.size(); } -void Node::addLabel (NodeLabel* gfxLabel ) { - //qDebug("NODE: add label"); - m_label=gfxLabel ; - m_hasLabel=true; +void Node::addLabel () { + qDebug()<< "Node::addLabel()" ; + m_label = new NodeLabel (this, m_labelText, m_labelSize); + m_label -> setDefaultTextColor (m_labelColor); + m_label -> setPos( m_size, m_labelDistance+m_size); + m_hasLabel = true; } + NodeLabel* Node::label(){ - return m_label; + if (!m_hasLabel) { + addLabel(); + } + return m_label; } void Node::deleteLabel(){ - qDebug ("Node: deleteLabel "); - m_hasLabel=false; - m_label->hide(); - graphicsWidget->removeItem(m_label); + qDebug ("Node: deleteLabel "); + if (m_hasLabel) { + m_hasLabel=false; + m_label->hide(); + graphicsWidget->removeItem(m_label); + } + qDebug () << "Node::deleteLabel() - finished"; + } -void Node::clearLabel(){ - m_hasLabel=false; +void Node::setLabelText ( QString label) { + qDebug()<< "Node::setLabelText()"; + prepareGeometryChange(); + m_labelText = label; + if (m_hasLabel) + m_label->setPlainText(label); + else + addLabel(); + m_hasLabel=true; } +void Node::setLabelVisibility(const bool &toggle) { + if (toggle){ + if (m_hasLabel) { + m_label->show(); + } + else { + addLabel(); + } + } + else { + if (m_hasLabel) { + m_label->hide(); + } + } + + m_hasLabel=toggle; +} + +void Node::setLabelSize(const int &size) { + m_labelSize = size; + if (!m_hasLabel) { + addLabel(); + } + m_label->setSize(m_labelSize); + +} + +/** + * @brief Node::labelText + * @return QString + */ +QString Node::labelText ( ) { + return m_labelText; +} + + + +/** + * @brief Node::setLabelDistance + * @param distance + */ +void Node::setLabelDistance(const int &distance) { + m_labelDistance = distance; + if (!m_hasLabel) { + addLabel(); + } + m_label->setPos( -m_size, m_size+m_labelDistance);; + +} + + -void Node::addNumber (NodeNumber *gfxNum ) { - m_number=gfxNum ; - m_hasNumber=true; +void Node::addNumber () { + qDebug()<<"Node::addNumber () " ; + m_hasNumber=true; + m_hasNumberInside = false; + m_number= new NodeNumber ( this, QString::number(m_num), m_numSize); + m_number -> setDefaultTextColor (m_numColor); + m_number -> setPos(m_size+m_numberDistance, 0); + +} + +NodeNumber* Node::number(){ + return m_number; } void Node::deleteNumber( ){ - qDebug ("Node: deleteNumber "); - m_number->hide(); - graphicsWidget->removeItem(m_number); + qDebug () << "Node::deleteNumber()"; + if (m_hasNumber && !m_hasNumberInside) { + m_number->hide(); + graphicsWidget->removeItem(m_number); + m_hasNumber=false; + } + qDebug () << "Node::deleteNumber() - finished"; } - Node::~Node(){ - qDebug() << "\n\n\n *** ~Node() "<< nodeNumber(); +void Node::setNumberVisibility(const bool &toggle) { + qDebug() << "Node::setNumberVisibility() " << toggle; + if (toggle) { //show + if (!m_hasNumber) { + m_hasNumber=toggle; + if ( !m_hasNumberInside ) + addNumber(); + else { + setShape(m_shape); + } + } + } + else { // hide + deleteNumber(); + m_hasNumber=toggle; + setShape(m_shape); + } + +} + +void Node::setNumberInside (const bool &toggle){ + qDebug()<<"Node::setNumberInside() " << toggle; + if (toggle) { // set number inside + deleteNumber(); + } + else { + addNumber(); + } + m_hasNumber = true; + m_hasNumberInside = toggle; + setShape(m_shape); +} + + +/** + * @brief Node::setNumberSize + * @param size + */ +void Node::setNumberSize(const int &size) { + m_numSize = size; + if (m_hasNumber && !m_hasNumberInside) { + m_number->setSize(m_numSize); + } + else if (m_hasNumber && m_hasNumberInside) { + setShape(m_shape); + } + else { + // create a nodeNumber ? + } + +} + + +/** + * @brief Node::setNumberColor + * @param color + */ +void Node::setNumberColor(const QString &color) { + m_numColor = color; + if (m_hasNumber){ + if (m_hasNumberInside) { + setShape(m_shape); + } + else { + m_number -> setDefaultTextColor (m_numColor); + } + } + +} + +/** + * @brief Node::setNumberDistance + * @param distance + */ +void Node::setNumberDistance(const int &distance) { + m_numberDistance = distance; + if (m_hasNumber && !m_hasNumberInside) { + m_number -> setPos( m_size+m_numberDistance, 0); + } + else if (m_hasNumber && m_hasNumberInside) { + // do nothing + } + else { + // create a nodeNumber ? + } + +} + + + + + +Node::~Node(){ + qDebug() << "*** ~Node() - node "<< nodeNumber() + << "inEdgeList.size = " << inEdgeList.size() + << "outEdgeList.size = " << outEdgeList.size(); + foreach (Edge *edge, inEdgeList) { qDebug("~Node: removing edges in inEdgeList"); - //edge->remove(); - graphicsWidget->removeItem(edge); + delete edge; + //graphicsWidget->removeItem(edge); } foreach (Edge *edge, outEdgeList) { qDebug("~Node: removing edges in outEdgeList"); - //edge->remove(); - graphicsWidget->removeItem(edge); + delete edge; + //graphicsWidget->removeItem(edge); } - - this->deleteNumber(); - this->deleteLabel(); + if ( m_hasNumber ) + deleteNumber(); + if ( m_hasLabel ) + deleteLabel(); inEdgeList.clear(); outEdgeList.clear(); this->hide(); graphicsWidget->removeItem(this); - } +} diff --git a/src/node.h b/src/node.h index 3e682043..0ba3c42d 100755 --- a/src/node.h +++ b/src/node.h @@ -5,7 +5,7 @@ node.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -53,79 +53,92 @@ static const int TypeNode = QGraphicsItem::UserType+1; // class Node : public QObject, public QGraphicsItem { - Q_OBJECT - Q_INTERFACES (QGraphicsItem) + Q_OBJECT + Q_INTERFACES (QGraphicsItem) public: - Node(GraphicsWidget*, int num, int size, QString col, QString shape, bool, int, int, QPointF p) ; + Node (GraphicsWidget* gw, const int &num, const int &size, + const QString &color, const QString &shape, + const bool &showNumbers, const bool &numbersInside, + const QString &numberColor, const int &numberSize, const int &numDistance, + const bool &showLabels, const QString &label, const QString &labelColor, + const int &labelSize, const int &labelDistance, + QPointF p + ); ~Node(); - enum { Type = UserType + 1 }; - int type() const { return Type; } + enum { Type = UserType + 1 }; + int type() const { return Type; } + QRectF boundingRect() const; + QPainterPath shape() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - QRectF boundingRect() const; - QPainterPath shape() const; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + long int nodeNumber() {return m_num;} - long int nodeNumber() {return m_num;} + void addInLink( Edge *edge ) ; + void deleteInLink(Edge*); + void addOutLink( Edge *edge ) ; + void deleteOutLink(Edge*); - void setSize(int); - int size(); + void setSize(const int &); + int size() const; void setShape (const QString); - QString nodeShape() {return m_shape;} + QString nodeShape() {return m_shape;} - void setColor(QString str); - void setColor(QColor color); - QString color (); - + void setColor(QString str); + void setColor(QColor color); + QString color (); + + void addLabel(); + NodeLabel* label(); + void deleteLabel(); + void setLabelVisibility(const bool &toggle); + void setLabelSize(const int &size); void setLabelText ( QString label) ; - QString labelText () ; // Used by GW:: hasNode() - NodeLabel* label(); - void addLabel (NodeLabel* gfxLabel ) ; - void deleteLabel(); - void clearLabel(); - - void addInLink( Edge *edge ) ; - void deleteInLink(Edge*); - - void addOutLink( Edge *edge ) ; - void deleteOutLink(Edge*); - - void setNumberInside(bool); - - void addNumber (NodeNumber *gfxNum ) ; - void deleteNumber(); - - void toggleAntialiasing(bool); - + QString labelText(); + void setLabelDistance(const int &distance); + + void addNumber () ; + NodeNumber* number(); + void deleteNumber(); + void setNumberVisibility(const bool &toggle); + void setNumberInside(const bool &toggle); + void setNumberSize(const int &size); + void setNumberDistance(const int &distance); + void setNumberColor(const QString &color); + + void toggleAntialiasing(bool); + + protected: - QVariant itemChange(GraphicsItemChange change, const QVariant &value); - void mousePressEvent(QGraphicsSceneMouseEvent *event); - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void hoverEnterEvent(QGraphicsSceneHoverEvent *event); + void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); signals: - void nodeClicked(Node*); - void openNodeContextMenu(); - void startEdge(Node *); - void adjustOutEdge(); - void adjustInEdge(); - void removeOutEdge(); - void removeInEdge(); + void nodeClicked(Node*); + void startEdge(Node *); + void adjustOutEdge(); + void adjustInEdge(); + void removeOutEdge(); + void removeInEdge(); private: - GraphicsWidget *graphicsWidget; - QPainterPath *m_path; - QPointF newPos; - QPolygon *m_poly_t, *m_poly_d; - int m_size, m_nd, m_ld; - long int m_num; - QString m_shape, m_col_str, m_labelIn; - QColor m_col; - bool m_hasNumber, m_hasLabel, m_isNumberInside; - /**Lists of elements attached to this node */ + GraphicsWidget *graphicsWidget; + QPainterPath *m_path; + QPointF newPos; + QPolygonF *m_poly_t; + int m_size, m_numSize, m_labelSize, m_numberDistance, m_labelDistance; + long int m_num; + QString m_shape, m_col_str, m_numColor, m_labelText, m_labelColor; + QColor m_col; + bool m_hasNumber, m_hasLabel, m_hasNumberInside; + /**Lists of elements attached to this node */ list inEdgeList, outEdgeList; - NodeLabel *m_label; - NodeNumber *m_number; + NodeLabel *m_label; + NodeNumber *m_number; }; #endif diff --git a/src/nodeeditdialog.cpp b/src/nodeeditdialog.cpp index 6601b238..4ab1d537 100644 --- a/src/nodeeditdialog.cpp +++ b/src/nodeeditdialog.cpp @@ -5,7 +5,7 @@ nodeeditdialog.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -113,6 +113,12 @@ void NodeEditDialog::gatherData(){ else if ( ui.triangleRadio->isChecked() ){ nodeShape = "triangle"; } + else if ( ui.starRadio->isChecked() ){ + nodeShape = "star"; + } + else { + nodeShape = "box"; + } emit userChoices(nodeLabel,nodeSize,nodeValue,nodeColor,nodeShape); } diff --git a/src/nodeeditdialog.h b/src/nodeeditdialog.h index e052f332..cea96ece 100644 --- a/src/nodeeditdialog.h +++ b/src/nodeeditdialog.h @@ -5,7 +5,7 @@ nodeeditdialog.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net diff --git a/src/nodelabel.cpp b/src/nodelabel.cpp index 92d29bcf..d289ec1d 100755 --- a/src/nodelabel.cpp +++ b/src/nodelabel.cpp @@ -1,11 +1,11 @@ /*************************************************************************** - SocNetV: Social Network Visualizer + SocNetV: Social Network Visualizer version: 2.0 Written in Qt nodelabel.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -29,18 +29,25 @@ #include -NodeLabel::NodeLabel( Node *jim , int size, QString labelText) :QGraphicsTextItem(0) { - source=jim; - jim -> addLabel(this); - setParentItem(jim); //auto disables child items like this, when node is disabled. - setPlainText( labelText ); +NodeLabel::NodeLabel(Node *jim , const QString &text, const int &size) : + QGraphicsTextItem(jim) { + source=jim; + setParentItem(jim); //auto disables child items like this, when node is disabled. + setPlainText( text ); setFont( QFont ("Times", size, QFont::Light, true) ); - setZValue (253); + setZValue (253); + setAcceptHoverEvents(false); } -void NodeLabel::removeRefs(){ - source->deleteLabel(); +void NodeLabel::setSize(const int &size) { + prepareGeometryChange(); + setFont( QFont ("Times", size, QFont::Black, false) ); + //update(); +} + +void NodeLabel::removeRefs(){ + source->deleteLabel(); } diff --git a/src/nodelabel.h b/src/nodelabel.h index 31a365bc..a504e08d 100755 --- a/src/nodelabel.h +++ b/src/nodelabel.h @@ -6,7 +6,7 @@ nodelabel.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -35,11 +35,12 @@ static const int TypeLabel = QGraphicsItem::UserType+4; class NodeLabel : public QGraphicsTextItem{ public: - NodeLabel(Node * , int size, QString); + NodeLabel(Node * , const QString &text, const int &size ); void removeRefs(); enum { Type = UserType + 4 }; int type() const { return Type; } + void setSize(const int &size); ~NodeLabel(); Node* node() { return source; } private: diff --git a/src/nodenumber.cpp b/src/nodenumber.cpp index 5d2ddc1e..b6eaf20e 100755 --- a/src/nodenumber.cpp +++ b/src/nodenumber.cpp @@ -1,11 +1,11 @@ /*************************************************************************** - SocNetV: Social Network Visualizer + SocNetV: Social Network Visualizer version: 2.0 Written in Qt nodenumber.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -28,17 +28,25 @@ #include "node.h" #include -NodeNumber::NodeNumber( Node *jim , int size, QString labelText) :QGraphicsTextItem(0) { - source=jim; - jim -> addNumber(this); - setParentItem(jim); //auto disables child items like this, when node is disabled. - setPlainText( labelText ); + +NodeNumber::NodeNumber( Node *jim , const QString &labelText, const int &size) + :QGraphicsTextItem(jim) { + source=jim; + setParentItem(jim); //auto disables child items like this, when node is disabled. + setPlainText( labelText ); + setFont( QFont ("Times", size, QFont::Black, false) ); + setZValue(254); + setAcceptHoverEvents(false); +} + +void NodeNumber::setSize(const int size) { + prepareGeometryChange(); setFont( QFont ("Times", size, QFont::Black, false) ); - setZValue(254); + //update(); } void NodeNumber::removeRefs(){ - source->deleteNumber(); + source->deleteNumber(); } diff --git a/src/nodenumber.h b/src/nodenumber.h index b7830986..6473bceb 100755 --- a/src/nodenumber.h +++ b/src/nodenumber.h @@ -5,7 +5,7 @@ nodenumber.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -37,11 +37,12 @@ static const int TypeNumber=QGraphicsItem::UserType+3; class NodeNumber : public QGraphicsTextItem { public: - NodeNumber(Node * , int, QString); + NodeNumber(Node * , const QString &labelText, const int &size); + enum { Type = UserType + 3 }; void removeRefs(); - enum { Type = UserType + 3 }; int type() const { return Type; } Node* node() { return source; } + void setSize(const int size); ~NodeNumber(); private: Node *source; diff --git a/src/parser.cpp b/src/parser.cpp index 32709ddc..54d82dda 100755 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5,7 +5,7 @@ parser.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -39,6 +39,8 @@ #include #include "graph.h" //needed for setParent +using namespace std; + Parser::Parser( const QString fn, const QString m_codec, const int iNS, const QString iNC, const QString iNSh, @@ -404,7 +406,7 @@ bool Parser::loadDL(){ << " source node counter is " << source << " and relation to " << relation<< ": " << relationCounter; - emit changeRelation (relationCounter); + emit relationSet (relationCounter); } else if (source>aNodes) { source=1; @@ -414,7 +416,7 @@ bool Parser::loadDL(){ << " init source node counter to " << source << " and relation to " << relation << ": " << relationCounter; - emit changeRelation (relationCounter); + emit relationSet (relationCounter); } else { qDebug() << "source node counter is " << source; @@ -429,12 +431,13 @@ bool Parser::loadDL(){ << " found edge from " << source << " to " << target << " weight " << edgeWeight - << " emitting createEdge() to parent" ; + << " emitting edgeCreate() to parent" ; undirected=0; arrows=true; bezier=false; - emit createEdge( source, target, edgeWeight, initEdgeColor, undirected, arrows, bezier); + emit edgeCreate( source, target, edgeWeight, initEdgeColor, + undirected, arrows, bezier); totalLinks++; qDebug() << "TotalLinks= " << totalLinks; @@ -478,7 +481,7 @@ bool Parser::loadDL(){ qDebug()<< " Parser::loadDL() - Creating link " << source << " -> "<< target << " weight= "<< edgeWeight << " TotalLinks= " << totalLinks+1; - emit createEdge(source, target, edgeWeight, initEdgeColor, undirected, arrows, bezier); + emit edgeCreate(source, target, edgeWeight, initEdgeColor, undirected, arrows, bezier); totalLinks++; } } @@ -490,7 +493,7 @@ bool Parser::loadDL(){ } //The network has been loaded. Tell MW the statistics and network type // 0: no format, 1: GraphML, 2:Pajek, 3:Adjacency, 4: Dot, 5:DL, 6:GML, 7: List - emit changeRelation (0); + emit relationSet (0); emit fileType(5, networkName, aNodes, totalLinks, undirected); qDebug() << "Parser-loadDL() clearing"; lineElement.clear(); labelsList.clear(); relationsList.clear(); @@ -512,14 +515,17 @@ bool Parser::loadPajek(){ nodeColor=""; edgeColor=""; nodeShape=""; + initEdgeLabel = QString::null; QStringList lineElement; bool ok=false, intOk=false, check1=false, check2=false; bool nodes_flag=false, edges_flag=false, arcs_flag=false, arcslist_flag=false, matrix_flag=false; fileContainsNodeColors=false; fileContainsNodeCoords=false; fileContainsLinkColors=false; + fileContainsLinkLabels=false; bool zero_flag=false; - int i=0, j=0, miss=0, source= -1, target=-1, nodeNum, colorIndex=-1, coordIndex=-1; + int i=0, j=0, miss=0, source= -1, target=-1, nodeNum, colorIndex=-1; + int coordIndex=-1, labelIndex=-1; unsigned long int lineCounter=0; int pos=-1, relationCounter=0; float weight=1; @@ -624,8 +630,8 @@ bool Parser::loadPajek(){ if (relationCounter > 0) { qDebug () << "Parser::loadPajek() relationCounter " << relationCounter - << "emitting changeRelation"; - emit changeRelation(relationCounter); + << "emitting relationSet"; + emit relationSet(relationCounter); i=0; // reset the source node index } relationCounter++; @@ -662,16 +668,17 @@ bool Parser::loadPajek(){ label=label.remove('\"'); //qDebug()<<"node label now: " << label.toLatin1(); - /** NODESHAPE: There are four possible . */ + /** NODESHAPE: There are five possible . */ if (str.contains("Ellipse", Qt::CaseInsensitive) ) nodeShape="ellipse"; else if (str.contains("circle", Qt::CaseInsensitive) ) nodeShape="circle"; else if (str.contains("box", Qt::CaseInsensitive) ) nodeShape="box"; + else if (str.contains("star", Qt::CaseInsensitive) ) nodeShape="star"; else if (str.contains("triangle", Qt::CaseInsensitive) ) nodeShape="triangle"; else nodeShape="diamond"; /** NODECOLORS */ //if there is an "ic" tag, a specific NodeColor for this node follows... if (str.contains("ic",Qt::CaseInsensitive)) { - for (register int c=0; c< lineElement.count(); c++) { + for (int c=0; c< lineElement.count(); c++) { if (lineElement[c] == "ic") { //the colourname is at c+1 position. nodeColor=lineElement[c+1]; @@ -692,7 +699,7 @@ bool Parser::loadPajek(){ } /**READ NODE COORDINATES */ if ( str.contains(".",Qt::CaseInsensitive) ) { - for (register int c=0; c< lineElement.count(); c++) { + for (int c=0; c< lineElement.count(); c++) { temp=lineElement.at(c); // qDebug()<< temp.toLatin1(); if ((coordIndex=temp.indexOf(".", Qt::CaseInsensitive)) != -1 ){ @@ -790,7 +797,7 @@ bool Parser::loadPajek(){ j=aNodes; } if (edges_flag && !arcs_flag) { /**EDGES */ - //qDebug("Parser-loadPajek(): ==== Reading edges ===="); + qDebug("Parser-loadPajek(): ==== Reading edges ===="); qDebug()<= lineElement.count()) edgeColor=initEdgeColor; else edgeColor=lineElement [ colorIndex ]; if (edgeColor.contains (".") ) edgeColor=initEdgeColor; @@ -825,11 +832,28 @@ bool Parser::loadPajek(){ //qDebug("Parser-loadPajek(): file with no link colours"); edgeColor=initEdgeColor; } + + if (lineElement.contains("l", Qt::CaseSensitive ) ) { + qDebug("Parser-loadPajek(): file with link labels"); + fileContainsLinkLabels=true; + labelIndex=lineElement.indexOf( QRegExp("[l]"), 0 ) + 1; + if (labelIndex >= lineElement.count()) edgeLabel=initEdgeLabel; + else edgeLabel=lineElement [ labelIndex ]; + if (edgeLabel.contains (".") ) edgeLabel=initEdgeLabel; + qDebug()<< " edge label "<< edgeLabel; + } + else { + //qDebug("Parser-loadPajek(): file with no link labels"); + edgeLabel=initEdgeLabel; + } + + undirected=2; - arrows=true; + arrows=false; bezier=false; qDebug()<< "Parser-loadPajek(): EDGES: Create edge between " << source << " - "<< target; - emit createEdge(source, target, edgeWeight, edgeColor, undirected, arrows, bezier); + emit edgeCreate(source, target, edgeWeight, edgeColor, + undirected, arrows, bezier, edgeLabel); totalLinks=totalLinks+2; } //end if EDGES @@ -862,11 +886,26 @@ bool Parser::loadPajek(){ //qDebug("Parser-loadPajek(): file with no link colours"); edgeColor=initEdgeColor; } + + if (lineElement.contains("l", Qt::CaseSensitive ) ) { + qDebug("Parser-loadPajek(): file with link labels"); + fileContainsLinkLabels=true; + labelIndex=lineElement.indexOf( QRegExp("[l]"), 0 ) + 1; + if (labelIndex >= lineElement.count()) edgeLabel=initEdgeLabel; + else edgeLabel=lineElement.at ( labelIndex ); + //if (edgeLabel.contains (".") ) edgeLabel=initEdgeLabel; + qDebug()<< " edge label "<< edgeLabel; + } + else { + //qDebug("Parser-loadPajek(): file with no link labels"); + edgeLabel=initEdgeLabel; + } undirected=0; arrows=true; bezier=false; qDebug()<<"Parser-loadPajek(): ARCS: Creating arc from node "<< source << " to node "<< target << " with weight "<< weight; - emit createEdge(source, target, edgeWeight , edgeColor, undirected, arrows, bezier); + emit edgeCreate(source, target, edgeWeight , edgeColor, + undirected, arrows, bezier, edgeLabel); totalLinks++; } //else if ARCS else if (arcslist_flag) { /** ARCSlist */ @@ -878,10 +917,10 @@ bool Parser::loadPajek(){ undirected=0; arrows=true; bezier=false; - for (register int index = 1; index < lineElement.size(); index++) { + for (int index = 1; index < lineElement.size(); index++) { target = lineElement.at(index).toInt(&ok,10); qDebug()<<"Parser-loadPajek(): ARCS LIST: Creating ARC source "<< source << " target "<< target << " with weight "<< weight; - emit createEdge(source, target, edgeWeight, edgeColor, undirected, arrows, bezier); + emit edgeCreate(source, target, edgeWeight, edgeColor, undirected, arrows, bezier); totalLinks++; } } //else if ARCSLIST @@ -900,7 +939,7 @@ bool Parser::loadPajek(){ qDebug()<<"Parser-loadPajek(): MATRIX: Creating arc source " << source << " target "<< target +1 << " with weight "<< weight; - emit createEdge(source, target+1, edgeWeight, edgeColor, + emit edgeCreate(source, target+1, edgeWeight, edgeColor, undirected, arrows, bezier); totalLinks++; } @@ -924,7 +963,7 @@ bool Parser::loadPajek(){ qDebug("Parser-loadPajek(): Clearing DumiesList from Pajek"); listDummiesPajek.clear(); relationsList.clear(); - emit changeRelation (0); + emit relationSet (0); return true; @@ -1032,7 +1071,7 @@ bool Parser::loadAdjacency(){ undirected=0; arrows=true; bezier=false; - emit createEdge(i+1, j+1, edgeWeight, initEdgeColor, undirected, arrows, bezier); + emit edgeCreate(i+1, j+1, edgeWeight, initEdgeColor, undirected, arrows, bezier); totalLinks++; qDebug() << "Parser-loadAdjacency(): Link from i=" << i+1 << " to j=" << j+1 << "weight=" << edgeWeight << ". TotalLinks= " << totalLinks; @@ -1122,7 +1161,6 @@ bool Parser::loadTwoModeSociomatrix(){ qDebug() << "Parser-loadTwoModeSociomatrix(): there is an 1 from "<< i << " to "<< j; firstModeMultiMap.insert(i, j); secondModeMultiMap.insert(j, i); - QList values; for (int k = 1; k < i ; ++k) { qDebug() << "Checking earlier discovered actor k = " << k; if ( firstModeMultiMap.contains(k, j) ) { @@ -1131,7 +1169,7 @@ bool Parser::loadTwoModeSociomatrix(){ bezier=false; edgeWeight = 1; qDebug() << " Actor " << i << " on the same event as actor " << k << ". Creating edge "; - emit createEdge(i, k, edgeWeight, initEdgeColor, undirected, arrows, bezier); + emit edgeCreate(i, k, edgeWeight, initEdgeColor, undirected, arrows, bezier); totalLinks++; } } @@ -1337,8 +1375,8 @@ void Parser::readGraphML(QXmlStreamReader &xml){ endGraphMLElementEdge(xml); } } - // call createEdgesMissingNodes() to create any edges with missing nodes - createEdgesMissingNodes(); + // call createMissingNodeEdges() to create any edges with missing nodes + createMissingNodeEdges(); } @@ -1352,14 +1390,17 @@ void Parser::readGraphMLElementGraph(QXmlStreamReader &xml){ QString defaultDirection = xmlStreamAttr.value("edgedefault").toString(); qDebug()<< " edgedefault "<< defaultDirection; if (defaultDirection=="undirected"){ + qDebug()<< " this is an undirected graph "; undirected = 2; arrows=false; } else { + qDebug()<< " this is a directed graph "; undirected = 0; arrows=true; } networkName = xmlStreamAttr.value("id").toString(); + emit addRelation( networkName); qDebug()<< " graph id " << networkName; //store graph id to return it afterwards } @@ -1372,7 +1413,7 @@ void Parser::readGraphMLElementGraph(QXmlStreamReader &xml){ bool Parser::xmlStreamHasAttribute( QXmlStreamAttributes &xmlStreamAttr, QString str) const { int size = xmlStreamAttr.size(); - for (register int i = 0 ; i < size ; i++) { + for (int i = 0 ; i < size ; i++) { qDebug() << " xmlStreamHasAttribute(): " << xmlStreamAttr.at(i).name().toString() << endl; if ( xmlStreamAttr.at(i).name() == str) @@ -1522,6 +1563,7 @@ void Parser::readGraphMLElementEdge(QXmlStreamAttributes &xmlStreamAttr){ missingNode=false; edgeWeight=initEdgeWeight; edgeColor=initEdgeColor; + edgeLabel = ""; bool_edge= true; if ( ((xmlStreamAttr.value("directed")).toString()).contains("false"),Qt::CaseInsensitive ) { @@ -1570,10 +1612,9 @@ void Parser::endGraphMLElementEdge(QXmlStreamReader &xml){ << " postponing edge creation signal"; return; } - qDebug()<<" Parser: endGraphMLElementEdge() *** signal createEdge " + qDebug()<<" Parser: endGraphMLElementEdge() *** signal edgeCreate " << source << " -> " << target << " undirected value " << undirected; - //FIXME need to return edge label as well! - emit createEdge(source, target, edgeWeight, edgeColor, undirected, arrows, bezier); + emit edgeCreate(source, target, edgeWeight, edgeColor, undirected, arrows, bezier, edgeLabel); totalLinks++; bool_edge= false; } @@ -1870,14 +1911,16 @@ void Parser::readGraphMLElementUnknown(QXmlStreamReader &xml) { } -void Parser::createEdgesMissingNodes(){ +void Parser::createMissingNodeEdges(){ + qDebug()<<"Parser::createMissingNodeEdges() "; int count=0; - bool ok; - edgeWeight = initEdgeWeight; - edgeColor = initEdgeColor; - undirected = 0; if ( (count = edgesMissingNodesHash.size()) > 0 ) { - qDebug()<<"Parser::createEdgesMissingNodes() - edges to create " << count; + + bool ok; + edgeWeight = initEdgeWeight; + edgeColor = initEdgeColor; + undirected = 0; + qDebug()<<"Parser::createMissingNodeEdges() - edges to create " << count; QHash::const_iterator it = edgesMissingNodesHash.constBegin(); while (it != edgesMissingNodesHash.constEnd()) { @@ -1903,15 +1946,18 @@ void Parser::createEdgesMissingNodes(){ undirected=2; } - qDebug()<<" Parser: createEdgesMissingNodesHash() *** signal createEdge " + qDebug()<<" Parser: createMissingNodeEdgesHash() *** signal edgeCreate " << source << " -> " << target << " undirected value " << undirected; - //FIXME need to return edge label as well! - emit createEdge(source, target, edgeWeight, edgeColor, undirected, arrows, bezier); + + emit edgeCreate(source, target, edgeWeight, edgeColor, undirected, arrows, bezier, edgeLabel); } ++it; } } + else { + qDebug()<<"Parser::createMissingNodeEdges() - nothing to do"; + } } @@ -2018,12 +2064,14 @@ bool Parser::loadDot(){ if ( str.contains("digraph", Qt::CaseInsensitive) ) { lineElement=str.split(" "); + undirected = 0; if (lineElement[1]!="{" ) networkName=lineElement[1]; qDebug() << "This is a DOT DIGRAPH named " << networkName; continue; } else if ( str.contains("graph", Qt::CaseInsensitive) ) { lineElement=str.split(" "); + undirected = 2; if (lineElement[1] !="{" ) networkName=lineElement[1]; qDebug() << "This is a DOT GRAPH named " << networkName; continue; @@ -2035,7 +2083,7 @@ bool Parser::loadDot(){ } if ( str.contains("graph [" ,Qt::CaseInsensitive) ) { - netProperties == true; + netProperties = true; Q_UNUSED(netProperties); } @@ -2256,7 +2304,7 @@ bool Parser::loadDot(){ target=aNodes; if (it!=nodeSequence.begin()) { qDebug()<<"-- Drawing Link between node "<< source<< " and node " <name(); - emit userCodec(fileName, codec->name(), format); + emit loadNetworkFileWithCodec(fileName, codec->name(), format); QDialog::accept(); } diff --git a/src/previewform.h b/src/previewform.h index 1cd78c97..998b8f6f 100644 --- a/src/previewform.h +++ b/src/previewform.h @@ -5,7 +5,7 @@ previewform.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -48,7 +48,7 @@ class PreviewForm : public QDialog void setEncodedData(const QByteArray &data, const QString, const int ); QString decodedString() const { return decodedStr; } signals: - void userCodec(const QString, const QString, const int); + void loadNetworkFileWithCodec(const QString, const QString, const int); private slots: void updateTextEdit(); void accept(); diff --git a/src/randerdosrenyidialog.cpp b/src/randerdosrenyidialog.cpp index d4dda5b3..f690302b 100644 --- a/src/randerdosrenyidialog.cpp +++ b/src/randerdosrenyidialog.cpp @@ -5,7 +5,7 @@ randerdosrenyidialog.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -36,7 +36,7 @@ #include "randerdosrenyidialog.h" -RandErdosRenyiDialog::RandErdosRenyiDialog(QWidget *parent ) : +RandErdosRenyiDialog::RandErdosRenyiDialog(QWidget *parent, const float eprob) : QDialog(parent) { @@ -47,7 +47,7 @@ RandErdosRenyiDialog::RandErdosRenyiDialog(QWidget *parent ) : nodes = 0; model = ""; edges = 0; - eprob = 0; + ui.probDoubleSpinBox->setValue(eprob); mode = ""; diag = false; @@ -64,11 +64,11 @@ RandErdosRenyiDialog::RandErdosRenyiDialog(QWidget *parent ) : connect (ui.gnmRadioButton, &QRadioButton::clicked, this, &RandErdosRenyiDialog::checkErrors); - //ui.gnpRadioButton->setChecked(true); + ui.gnpRadioButton->setChecked(true); ui.probDoubleSpinBox->setEnabled(true); ui.edgesSpinBox-> setDisabled(true); ui.undirectedRadioButton->setChecked(true); - ui.diagCheckBox ->setChecked(true); + ui.diagCheckBox ->setChecked(false); connect (ui.gnpRadioButton, &QRadioButton::clicked, @@ -129,13 +129,13 @@ void RandErdosRenyiDialog::checkErrors() { ui.gnpRadioButton->setGraphicsEffect(effect); ui.gnmRadioButton->setGraphicsEffect(effect2); (ui.buttonBox) -> button (QDialogButtonBox::Ok) -> setEnabled(false); + return; } else { ui.gnpRadioButton->setGraphicsEffect(0); ui.gnmRadioButton->setGraphicsEffect(0); (ui.buttonBox) -> button (QDialogButtonBox::Ok) -> setEnabled(true); } - //gatherData(); } void RandErdosRenyiDialog::gatherData() { @@ -143,7 +143,7 @@ void RandErdosRenyiDialog::gatherData() { nodes = ui.nodesSpinBox->value(); model = ( ui.gnpRadioButton->isChecked() ) ? "G(n,p)" : "G(n,M)"; if ( ui.gnpRadioButton->isChecked() ) { - eprob = ui.probDoubleSpinBox->value(); +// eprob = ui.probDoubleSpinBox->value(); } else { edges = ui.edgesSpinBox->value(); @@ -152,10 +152,10 @@ void RandErdosRenyiDialog::gatherData() { diag = (ui.diagCheckBox -> isChecked() ? true : false); qDebug() << "nodes " << nodes ; qDebug() << "model " << model; - qDebug() << "eprob " << eprob; + qDebug() << "eprob " << ui.probDoubleSpinBox->value(); qDebug() << "edges " << edges; qDebug() << "mode " << mode; qDebug() << "diag " << diag; - emit userChoices(nodes, model, edges, eprob, mode, diag); + emit userChoices(nodes, model, edges, ui.probDoubleSpinBox->value(), mode, diag); } diff --git a/src/randerdosrenyidialog.h b/src/randerdosrenyidialog.h index 35b263aa..c26f3bc7 100644 --- a/src/randerdosrenyidialog.h +++ b/src/randerdosrenyidialog.h @@ -5,7 +5,7 @@ randerdosrenyidialog.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -38,7 +38,7 @@ class RandErdosRenyiDialog : public QDialog { Q_OBJECT public: - explicit RandErdosRenyiDialog(QWidget *parent=0); + explicit RandErdosRenyiDialog(QWidget *parent=0, const float eprob = 0); public slots: void checkErrors(); @@ -60,7 +60,7 @@ public slots: QString model; QString mode; int nodes, edges; - float eprob; + bool diag; Ui::RandErdosRenyiDialog ui; }; diff --git a/src/randsmallworlddialog.cpp b/src/randsmallworlddialog.cpp index 4ef52b28..d5dfa4e0 100644 --- a/src/randsmallworlddialog.cpp +++ b/src/randsmallworlddialog.cpp @@ -5,7 +5,7 @@ randsmallworlddialog.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -33,6 +33,7 @@ #include #include #include +#include #include "randsmallworlddialog.h" @@ -43,10 +44,10 @@ RandSmallWorldDialog::RandSmallWorldDialog(QWidget *parent) : ui.setupUi(this); - nodes = 0; - degree = 0; + nodes = 100; + degree = qCeil ( qLn (nodes) ); bprob = 0; - mode = ""; + mode = "undirected"; diag = false; connect ( ui.buttonBox, &QDialogButtonBox::accepted, @@ -54,8 +55,6 @@ RandSmallWorldDialog::RandSmallWorldDialog(QWidget *parent) : ui.buttonBox -> button (QDialogButtonBox::Ok) -> setDefault(true); - (ui.nodesSpinBox )->setFocus(); - ui.probDoubleSpinBox->setEnabled(true); ui.degreeSpinBox-> setEnabled(true); ui.undirectedRadioButton->setChecked(true); @@ -70,9 +69,22 @@ RandSmallWorldDialog::RandSmallWorldDialog(QWidget *parent) : connect ( ui.diagCheckBox,&QCheckBox::clicked, this, &RandSmallWorldDialog::setDiag); + + connect(ui.nodesSpinBox, SIGNAL(valueChanged(int)), + this, SLOT(modifyDegree(int))); + + ui.nodesSpinBox->setFocus(); + ui.nodesSpinBox->setValue(nodes); + ui.degreeSpinBox->setValue( degree ); + } +void RandSmallWorldDialog::modifyDegree(int value) { + ui.degreeSpinBox->setValue( qCeil ( qLn (value) )); + ui.degreeSpinBox->setMaximum( value ); +} + void RandSmallWorldDialog::setModeDirected (){ ui.directedRadioButton->setChecked(true) ; ui.undirectedRadioButton->setChecked(false) ; diff --git a/src/randsmallworlddialog.h b/src/randsmallworlddialog.h index 7d42667d..df20fd4b 100644 --- a/src/randsmallworlddialog.h +++ b/src/randsmallworlddialog.h @@ -5,7 +5,7 @@ randsmallworlddialog.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net @@ -46,6 +46,7 @@ public slots: void setModeDirected(); void setModeUndirected(); void setDiag(); + void modifyDegree(int value); signals: void userChoices( const int nodes, diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp new file mode 100644 index 00000000..07febe24 --- /dev/null +++ b/src/settingsdialog.cpp @@ -0,0 +1,632 @@ +/*************************************************************************** + SocNetV: Social Network Visualizer + version: 2.0 + Written in Qt + + settingsdialog.cpp - description + ------------------- + copyright : (C) 2005-2016 by Dimitris B. Kalamaras + email : dimitris.kalamaras@gmail.com + ***************************************************************************/ + +/******************************************************************************* +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 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 . * +********************************************************************************/ + +#include "settingsdialog.h" +#include "ui_settingsdialog.h" +#include +#include +#include +#include +#include +#include + +SettingsDialog::SettingsDialog( + QMap &appSettings, + QWidget *parent) : + QDialog(parent), + m_appSettings(appSettings), + ui(new Ui::SettingsDialog) +{ + ui->setupUi(this); + + // m_appSettings = appSettings; //only use if var passed by pointer + + //data export + ui->dataDirEdit->setText( (m_appSettings)["dataDir"]); + + //debugging + ui->printDebugChkBox->setChecked( + (appSettings["printDebug"] == "true") ? true:false + ); + + ui->progressBarsChkBox->setChecked( + (appSettings["showProgressBar"] == "true") ? true:false + ); + + /** + * canvas options + */ + ui->antialiasingChkBox->setChecked( + (appSettings["antialiasing"] == "true") ? true:false + ); + ui->printLogoChkBox->setChecked( + (appSettings["printLogo"] == "true") ? true:false + ); + + m_bgColor = QColor (m_appSettings["initBackgroundColor"]); + m_pixmap = QPixmap(60,20) ; + m_pixmap.fill( m_bgColor ); + ui->bgColorButton->setIcon(QIcon(m_pixmap)); + + ui->bgImageSelectEdit->setText((m_appSettings)["initBackgroundImage"]); + + /** + * window options + */ + ui->leftPanelChkBox->setChecked( + ( appSettings["showLeftPanel"] == "true") ? true:false + ); + + ui->rightPanelChkBox->setChecked( + ( appSettings["showRightPanel"] == "true") ? true:false + ); + + /** + * node options + */ + m_nodeColor = QColor (m_appSettings["initNodeColor"]); + m_pixmap = QPixmap(60,20) ; + m_pixmap.fill( m_nodeColor ); + ui->nodeColorBtn->setIcon(QIcon(m_pixmap)); + + if (m_appSettings["initNodeShape"] == "box") { + ui->nodeShapeRadioBox->setChecked(true); + } + else if (m_appSettings["initNodeShape"] == "circle") { + ui->nodeShapeRadioCircle->setChecked(true); + } + else if (m_appSettings["initNodeShape"] == "diamond") { + ui->nodeShapeRadioDiamond->setChecked(true); + } + else if (m_appSettings["initNodeShape"] == "ellipse") { + ui->nodeShapeRadioEllipse->setChecked(true); + } + else if (m_appSettings["initNodeShape"] == "triangle") { + ui->nodeShapeRadioTriangle->setChecked(true); + } + else if (m_appSettings["initNodeShape"] == "star") { + ui->nodeShapeRadioStar->setChecked(true); + } + else { // default + ui->nodeShapeRadioCircle->setChecked(true); + } + + ui->nodeSizeSpin->setValue( m_appSettings["initNodeSize"].toInt(0, 10) ); + + ui->nodeNumbersChkBox->setChecked( + ( m_appSettings["initNodeNumbersVisibility"] == "true") ? true : false + ); + + ui->nodeNumbersInsideChkBox->setChecked( + (m_appSettings["initNodeNumbersInside"] == "true" ) ? true:false + ); + if (m_appSettings["initNodeNumbersInside"] == "true") { + ui->nodeNumberDistanceSpin->setEnabled(false); + ui->nodeNumberSizeSpin->setValue( 0 ); + + } + m_nodeNumberColor = QColor (m_appSettings["initNodeNumberColor"]); + m_pixmap = QPixmap(60,20) ; + m_pixmap.fill( m_nodeNumberColor ); + ui->nodeNumberColorBtn->setIcon(QIcon(m_pixmap)); + + ui->nodeNumberSizeSpin->setValue( m_appSettings["initNodeNumberSize"].toInt(0, 10) ); + ui->nodeNumberDistanceSpin->setValue( m_appSettings["initNodeNumberDistance"].toInt(0, 10) ); + + + ui->nodeLabelsChkBox->setChecked( + ( m_appSettings["initNodeLabelsVisibility"] == "true") ? true : false + ); + + ui->nodeLabelSizeSpin->setValue( m_appSettings["initNodeLabelSize"].toInt(0, 10) ); + + m_nodeLabelColor = QColor (m_appSettings["initNodeLabelColor"]); + m_pixmap = QPixmap(60,20) ; + m_pixmap.fill( m_nodeLabelColor ); + ui->nodeLabelColorBtn->setIcon(QIcon(m_pixmap)); + + ui->nodeLabelDistanceSpin->setValue( m_appSettings["initNodeLabelDistance"].toInt(0, 10) ); + + + /** + * edge options + */ + + ui->edgesChkBox-> setChecked( + (m_appSettings["initEdgesVisibility"] == "true") ? true: false + ); + m_edgeColor = QColor (m_appSettings["initEdgeColor"]); + m_pixmap = QPixmap(60,20) ; + m_pixmap.fill( m_edgeColor ); + ui->edgeColorBtn->setIcon(QIcon(m_pixmap)); + + m_edgeColorNegative = QColor (m_appSettings["initEdgeColorNegative"]); + m_pixmap = QPixmap(60,20) ; + m_pixmap.fill( m_edgeColorNegative ); + ui->edgeColorNegativeBtn ->setIcon(QIcon(m_pixmap)); + + + if (m_appSettings["initEdgeShape"] == "line") { + ui->edgeShapeRadioStraightLine->setChecked(true); + } + else if (m_appSettings["initEdgeShape"] == "bezier") { + ui->edgeShapeRadioBezier->setChecked(true); + } + else { + ui->edgeShapeRadioStraightLine->setChecked(true); + } + + + ui->edgeWeightNumbersChkBox-> setChecked( + (m_appSettings["initEdgeWeightNumbersVisibility"] == "true") ? true: false + ); + m_edgeWeightNumberColor = QColor (m_appSettings["initEdgeWeightNumberColor"]); + m_pixmap = QPixmap(60,20) ; + m_pixmap.fill( m_edgeWeightNumberColor ); + ui->edgeWeightNumberColorBtn->setIcon(QIcon(m_pixmap)); + + ui->edgeWeightNumberSizeSpin->setValue( m_appSettings["initEdgeWeightNumberSize"].toInt(0, 10) ); + + + ui->edgeLabelsChkBox-> setChecked( + (m_appSettings["initEdgeLabelsVisibility"] == "true") ? true: false + ); + /** + * dialog signals to slots + */ + connect (ui->dataDirSelectButton, &QToolButton::clicked, + this, &SettingsDialog::getDataDir); + + connect (ui->printDebugChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setDebugMsgs); + + connect (ui->antialiasingChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setAntialiasing); + + connect (ui->printLogoChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setPrintLogo); + + connect (ui->bgColorButton, &QToolButton::clicked, + this, &SettingsDialog::getBgColor); + + connect (ui->bgImageSelectButton, &QToolButton::clicked, + this, &SettingsDialog::getBgImage); + + connect (ui->progressBarsChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setProgressBars); + + connect (ui->showToolBarChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setToolBar); + + connect (ui->showStatusBarChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setStatusBar); + + connect (ui->leftPanelChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setLeftPanel); + + connect (ui->rightPanelChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::setRightPanel); + + connect (ui->nodeShapeRadioBox, &QRadioButton::clicked, + this, &SettingsDialog::getNodeShape); + connect (ui->nodeShapeRadioCircle, &QRadioButton::clicked, + this, &SettingsDialog::getNodeShape); + connect (ui->nodeShapeRadioDiamond, &QRadioButton::clicked, + this, &SettingsDialog::getNodeShape); + connect (ui->nodeShapeRadioEllipse, &QRadioButton::clicked, + this, &SettingsDialog::getNodeShape); + connect (ui->nodeShapeRadioTriangle, &QRadioButton::clicked, + this, &SettingsDialog::getNodeShape); + connect (ui->nodeShapeRadioStar, &QRadioButton::clicked, + this, &SettingsDialog::getNodeShape); + + + connect(ui->nodeSizeSpin, SIGNAL(valueChanged(int)), + this, SLOT(getNodeSize(int)) ); + + connect ( ui->buttonBox, &QDialogButtonBox::accepted, + this, &SettingsDialog::validateSettings ); + + connect (ui->nodeColorBtn, &QToolButton::clicked, + this, &SettingsDialog::getNodeColor); + + + connect (ui->nodeNumbersChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::getNodeNumbersVisibility); + connect (ui->nodeNumbersInsideChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::getNodeNumbersInside); + connect (ui->nodeNumberColorBtn, &QToolButton::clicked, + this, &SettingsDialog::getNodeNumberColor); + connect(ui->nodeNumberSizeSpin, SIGNAL(valueChanged(int)), + this, SLOT(getNodeNumberSize(int)) ); + connect(ui->nodeNumberDistanceSpin, SIGNAL(valueChanged(int)), + this, SLOT(getNodeNumberDistance(int)) ); + + connect (ui->nodeLabelsChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::getNodeLabelsVisibility); + connect(ui->nodeLabelSizeSpin, SIGNAL(valueChanged(int)), + this, SLOT(getNodeLabelSize(int)) ); + connect (ui->nodeLabelColorBtn, &QToolButton::clicked, + this, &SettingsDialog::getNodeLabelColor); + connect(ui->nodeLabelDistanceSpin, SIGNAL(valueChanged(int)), + this, SLOT(getNodeLabelDistance(int)) ); + + + connect (ui->edgesChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::getEdgesVisibility); + connect (ui->edgeColorBtn, &QToolButton::clicked, + this, &SettingsDialog::getEdgeColor); + connect (ui->edgeColorNegativeBtn, &QToolButton::clicked, + this, &SettingsDialog::getEdgeColorNegative); + connect (ui->edgeShapeRadioStraightLine, &QRadioButton::clicked, + this, &SettingsDialog::getEdgeShape); + connect (ui->edgeShapeRadioBezier, &QRadioButton::clicked, + this, &SettingsDialog::getEdgeShape); + + connect (ui->edgeWeightNumbersChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::getEdgeWeightNumbersVisibility); + + + connect (ui->edgeLabelsChkBox, &QCheckBox::stateChanged, + this, &SettingsDialog::getEdgeLabelsVisibility); + +} + + +/** + * @brief SettingsDialog::validateSettings + * Validates form data and signals saveSettings to MW + */ +void SettingsDialog::validateSettings(){ + emit saveSettings(); + +} + +void SettingsDialog::getDataDir(){ + + QString m_dataDir = QFileDialog::getExistingDirectory(this, tr("Select a new data dir"), + ui->dataDirEdit->text(), + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks); + if (!m_dataDir.isEmpty()) { + if (!m_dataDir.endsWith( QDir::separator() )) { + m_dataDir += QDir::separator(); + } + ui->dataDirEdit->setText(m_dataDir); + m_appSettings["dataDir"]= m_dataDir; + } + +} + + +/** + * @brief SettingsDialog::getBgColor + * Opens a QColorDialog for the user to select a new bg color + */ +void SettingsDialog::getBgColor(){ + + m_bgColor = QColorDialog::getColor( + m_bgColor, this, tr("Select a background color") ); + if ( m_bgColor.isValid()) { + m_pixmap.fill(m_bgColor); + ui->bgColorButton->setIcon(QIcon(m_pixmap)); + ui->bgImageSelectEdit->setText(""); + m_appSettings["initBackgroundColor"] = m_bgColor.name(); + m_appSettings["initBackgroundImage"] = ""; + emit setBgColor(m_bgColor); + } + else { + // user pressed Cancel + } + +} + + + +/** + * @brief SettingsDialog::getBgImage + */ +void SettingsDialog::getBgImage(){ + QString m_bgImage = QFileDialog::getOpenFileName( + this, tr("Select a background image "), (m_appSettings)["lastUsedDirPath"], + tr("All (*);;PNG (*.png);;JPG (*.jpg)") + ); + if (!m_bgImage.isEmpty() ) { + (m_appSettings)["initBackgroundImage"] = m_bgImage ; + ui->bgImageSelectEdit->setText((m_appSettings)["initBackgroundImage"]); + emit setBgImage(); + } + else { //user pressed Cancel + + } + +} + + +/** + * @brief SettingsDialog::getNodeColor + * * Opens a QColorDialog for the user to select a new node color + */ +void SettingsDialog::getNodeColor(){ + m_nodeColor = QColorDialog::getColor( + m_nodeColor, this, tr("Select a color for Nodes") ); + if ( m_nodeColor.isValid()) { + m_pixmap.fill(m_nodeColor); + ui->nodeColorBtn->setIcon(QIcon(m_pixmap)); + (m_appSettings)["initNodeColor"] = m_nodeColor.name(); + emit setNodeColor(m_nodeColor); + } + else { + // user pressed Cancel + } +} + + +/** + * @brief SettingsDialog::getNodeShape + */ +void SettingsDialog::getNodeShape(){ + + QString nodeShape; + if ( ui->nodeShapeRadioBox->isChecked () ){ + m_appSettings["initNodeShape"] = "box"; + } + else if ( ui->nodeShapeRadioCircle->isChecked() ){ + m_appSettings["initNodeShape"] = "circle"; + } + else if ( ui->nodeShapeRadioDiamond->isChecked() ){ + m_appSettings["initNodeShape"] = "diamond"; + } + else if ( ui->nodeShapeRadioEllipse->isChecked() ){ + m_appSettings["initNodeShape"] = "ellipse"; + } + else if ( ui->nodeShapeRadioTriangle->isChecked() ){ + m_appSettings["initNodeShape"] = "triangle"; + } + else if ( ui->nodeShapeRadioStar->isChecked() ){ + m_appSettings["initNodeShape"] = "star"; + } + else { + m_appSettings["initNodeShape"] = "box"; + } + qDebug()<< "SettingsDialog::getNodeShape() - new default shape " << nodeShape; + emit setNodeShape(m_appSettings["initNodeShape"], 0); +} + + +/** + * @brief SettingsDialog::getNodeSize + * @param size + */ +void SettingsDialog::getNodeSize( int size) { + m_appSettings["initNodeSize"]= QString::number(size); + emit setNodeSize(size, false); +} + + +/** + * @brief SettingsDialog::getNodeNumbersVisibility + * @param toggle + */ +void SettingsDialog::getNodeNumbersVisibility (bool toggle){ + m_appSettings["initNodeNumbersVisibility"]= (toggle) ? "true" : "false"; + emit setNodeNumbersVisibility(toggle); +} + +/** + * @brief SettingsDialog::getNodeNumbersInside + * @param toggle + */ +void SettingsDialog::getNodeNumbersInside(bool toggle) { + m_appSettings["initNodeNumbersInside"]= (toggle) ? "true" : "false"; + ui->nodeNumbersChkBox->setChecked(true); + ui->nodeNumberDistanceSpin->setEnabled(!toggle); + ui->nodeNumberSizeSpin->setValue( ( (toggle) ? 0 : 7) ); + emit setNodeNumbersInside(toggle); +} + +/** + * @brief SettingsDialog::getNodeNumberSize + * @param size + */ +void SettingsDialog::getNodeNumberSize( const int size) { + m_appSettings["initNodeNumberSize"]= QString::number(size); + emit setNodeNumberSize(0, size, false); +} + +/** + * @brief SettingsDialog::getNodeNumberDistance + * @param distance + */ +void SettingsDialog::getNodeNumberDistance(const int distance) { + m_appSettings["initNodeNumberDistance"]= QString::number(distance); + emit setNodeNumberDistance(0, distance); +} + +/** + * @brief SettingsDialog::getNodeNumberColor + * * Opens a QColorDialog for the user to select a new node number color + */ +void SettingsDialog::getNodeNumberColor(){ + m_nodeNumberColor = QColorDialog::getColor( + m_nodeNumberColor, this, tr("Select color for Node Numbers") ); + if ( m_nodeNumberColor.isValid()) { + m_pixmap.fill(m_nodeNumberColor); + ui->nodeNumberColorBtn->setIcon(QIcon(m_pixmap)); + (m_appSettings)["initNodeNumberColor"] = m_nodeNumberColor.name(); + emit setNodeNumberColor(m_nodeNumberColor); + } + else { + // user pressed Cancel + } +} + + + + +/** + * @brief SettingsDialog::getNodeLabelsVisibility + * @param toggle + */ +void SettingsDialog::getNodeLabelsVisibility (bool toggle){ + m_appSettings["initNodeLabelsVisibility"]= (toggle) ? "true" : "false"; + emit setNodeLabelsVisibility(toggle); +} + + +/** + * @brief SettingsDialog::getNodeLabelColor + * * Opens a QColorDialog for the user to select a new node Label color + */ +void SettingsDialog::getNodeLabelColor(){ + m_nodeLabelColor = QColorDialog::getColor( + m_nodeLabelColor, this, tr("Select color for Node Labels") ); + if ( m_nodeLabelColor.isValid()) { + m_pixmap.fill(m_nodeLabelColor); + ui->nodeLabelColorBtn->setIcon(QIcon(m_pixmap)); + (m_appSettings)["initNodeLabelColor"] = m_nodeLabelColor.name(); + emit setNodeLabelColor(m_nodeLabelColor); + } + else { + // user pressed Cancel + } +} + +/** + * @brief SettingsDialog::getNodeLabelSize + * @param size + */ +void SettingsDialog::getNodeLabelSize( const int size) { + m_appSettings["initNodeLabelSize"]= QString::number(size); + emit setNodeLabelSize(0, size); +} + + +/** + * @brief SettingsDialog::getNodeLabelDistance + * @param distance + */ +void SettingsDialog::getNodeLabelDistance(const int distance) { + m_appSettings["initNodeLabelDistance"]= QString::number(distance); + emit setNodeLabelDistance(0, distance); +} + + + + +/** + * @brief SettingsDialog::getEdgesVisibility + * @param toggle + */ +void SettingsDialog::getEdgesVisibility (const bool &toggle){ + m_appSettings["initEdgesVisibility"]= (toggle) ? "true" : "false"; + emit setEdgesVisibility(toggle); +} + + +/** + * @brief SettingsDialog::getEdgeColor + * * Opens a QColorDialog for the user to select a new edge color + */ +void SettingsDialog::getEdgeColor(){ + m_edgeColor = QColorDialog::getColor( + m_edgeColor, this, tr("Select color for Edges ") ); + if ( m_edgeColor.isValid()) { + m_pixmap.fill(m_edgeColor); + ui->edgeColorBtn->setIcon(QIcon(m_pixmap)); + (m_appSettings)["initEdgeColor"] = m_edgeColor.name(); + emit setEdgeColor(m_edgeColor, RAND_MAX); + } + else { + // user pressed Cancel + } +} + + +/** + * @brief SettingsDialog::getEdgeColorNegative + * * Opens a QColorDialog for the user to select a new edge color + */ +void SettingsDialog::getEdgeColorNegative(){ + m_edgeColorNegative = QColorDialog::getColor( + m_edgeColorNegative, this, tr("Select color for negative Edges") ); + if ( m_edgeColorNegative.isValid()) { + m_pixmap.fill(m_edgeColorNegative); + ui->edgeColorNegativeBtn->setIcon(QIcon(m_pixmap)); + (m_appSettings)["initEdgeColorNegative"] = m_edgeColorNegative.name(); + emit setEdgeColor(m_edgeColorNegative, 0); + } + else { + // user pressed Cancel + } +} + + + +/** + * @brief SettingsDialog::getEdgeShape + */ +void SettingsDialog::getEdgeShape(){ + + if ( ui->edgeShapeRadioStraightLine->isChecked () ){ + m_appSettings["initEdgeShape"] = "line"; + } + else if ( ui->edgeShapeRadioBezier->isChecked() ){ + m_appSettings["initEdgeShape"] = "bezier"; + } + qDebug()<< "SettingsDialog::getEdgeShape() - new default shape " << + m_appSettings["initEdgeShape"]; + emit setEdgeShape(m_appSettings["initEdgeShape"], 0); +} + + + +/** + * @brief SettingsDialog::getEdgeWeightNumbersVisibility + * @param toggle + */ +void SettingsDialog::getEdgeWeightNumbersVisibility(const bool &toggle){ + m_appSettings["initEdgeWeightNumbersVisibility"]= (toggle) ? "true" : "false"; + emit setEdgeWeightNumbersVisibility(toggle); +} + + + +/** + * @brief SettingsDialog::getEdgeLabelsVisibility + * @param toggle + */ +void SettingsDialog::getEdgeLabelsVisibility(const bool &toggle){ + m_appSettings["initEdgeLabelsVisibility"]= (toggle) ? "true" : "false"; + emit setEdgeLabelsVisibility(toggle); +} + + + +SettingsDialog::~SettingsDialog() +{ + delete ui; +} diff --git a/src/settingsdialog.h b/src/settingsdialog.h new file mode 100644 index 00000000..b145087b --- /dev/null +++ b/src/settingsdialog.h @@ -0,0 +1,108 @@ +/*************************************************************************** + SocNetV: Social Network Visualizer + version: 2.0 + Written in Qt + + settingsdialog.h - description + ------------------- + copyright : (C) 2005-2016 by Dimitris B. Kalamaras + email : dimitris.kalamaras@gmail.com + ***************************************************************************/ + +/******************************************************************************* +* This program is free software: you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation, either version 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 . * +********************************************************************************/ + +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include +#include + +namespace Ui { +class SettingsDialog; +} + +class SettingsDialog : public QDialog +{ + Q_OBJECT + + +public: + explicit SettingsDialog(QMap &appSettings, QWidget *parent = 0 ); + ~SettingsDialog(); + +public slots: + void getDataDir(); + void getBgColor(); + void getBgImage(); + void validateSettings(); + void getNodeColor(); + void getNodeShape(); + void getNodeSize(int); + void getNodeNumbersVisibility (bool toggle); + void getNodeNumbersInside(bool toggle); + void getNodeNumberColor(); + void getNodeNumberSize(const int); + void getNodeNumberDistance(const int); + void getNodeLabelsVisibility (bool toggle); + void getNodeLabelColor(); + void getNodeLabelSize(const int); + void getNodeLabelDistance(const int); + void getEdgesVisibility (const bool &toggle); + void getEdgeColor(); + void getEdgeColorNegative(); + void getEdgeShape(); + void getEdgeWeightNumbersVisibility(const bool &toggle); + void getEdgeLabelsVisibility(const bool &toggle); + +signals: + void setProgressBars(bool); + void setToolBar(bool); + void setStatusBar(bool); + void setAntialiasing(bool); + void setPrintLogo(bool); + void setDebugMsgs(bool); + void setBgColor(const QColor); + void setBgImage(); + void setRightPanel(bool); + void setLeftPanel(bool); + void setNodeColor(QColor); + void setNodeShape(const QString, const long int); + void setNodeSize(int, const bool &); + void setNodeNumbersVisibility(bool); + void setNodeNumbersInside(bool); + void setNodeNumberSize(const int v, const int &size, const bool prompt); + void setNodeNumberDistance(const int v, const int &); + void setNodeNumberColor(const QColor); + void setNodeLabelsVisibility(const bool &); + void setNodeLabelColor(const QColor); + void setNodeLabelSize(const int v, const int &); + void setNodeLabelDistance(const int v, const int &); + void setEdgesVisibility (const bool &toggle); + void setEdgeColor(const QColor, const int &); + void setEdgeShape(const QString, const long int); + void setEdgeWeightNumbersVisibility(const bool &toggle); + void setEdgeLabelsVisibility(const bool &toggle); + void saveSettings(); +private: + QMap &m_appSettings ; + Ui::SettingsDialog *ui; + QPixmap m_pixmap; + //QString m_nodeShape; + QColor m_bgColor, m_nodeColor, m_nodeNumberColor, m_nodeLabelColor; + QColor m_edgeColor, m_edgeColorNegative, m_edgeWeightNumberColor; +}; + +#endif // SETTINGSDIALOG_H diff --git a/src/src.qrc b/src/src.qrc index cabd62d9..1f5a9149 100755 --- a/src/src.qrc +++ b/src/src.qrc @@ -71,5 +71,19 @@ images/import.png images/force.png images/scalefree.png + images/rotateleft.png + images/rotateright.png + images/appsettings.png + images/spider.png + images/image.png + images/pdf.png + images/reset.png + images/socnetv-logo.png + images/star.png + images/help-hint.png + images/bugs.png + images/edgeweight.png + images/qt.png + images/download.png diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 9a3d6f8a..2caeb1e1 100755 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -5,7 +5,7 @@ Written in Qt texteditor.cpp ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com *****************************************************************************/ @@ -88,7 +88,9 @@ bool TextEditor::save() bool TextEditor::saveAs() { - QString fileName = QFileDialog::getSaveFileName(this); + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save file"), + curFile); if (fileName.isEmpty()) return false; @@ -236,7 +238,7 @@ void TextEditor::loadFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { - QMessageBox::warning(this, tr("Application"), + QMessageBox::warning(this, tr("SocNetV Editor"), tr("Cannot read file %1:\n%2.") .arg(fileName) .arg(file.errorString())); @@ -257,7 +259,7 @@ bool TextEditor::saveFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) { - QMessageBox::warning(this, tr("TextEditor"), + QMessageBox::warning(this, tr("SocNetV Editor"), tr("Cannot write file %1:\n%2.") .arg(fileName) .arg(file.errorString())); @@ -288,7 +290,7 @@ void TextEditor::setCurrentFile(const QString &fileName) else shownName = strippedName(curFile); - setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("TextEditor"))); + setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("SocNetV Editor"))); } QString TextEditor::strippedName(const QString &fullFileName) diff --git a/src/texteditor.h b/src/texteditor.h index f982e95a..8a2cf24d 100755 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -5,7 +5,7 @@ Written in Qt texteditor.h ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com *****************************************************************************/ diff --git a/src/vertex.cpp b/src/vertex.cpp index c630e56b..6aaeab4f 100755 --- a/src/vertex.cpp +++ b/src/vertex.cpp @@ -5,7 +5,7 @@ vertex.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -58,9 +58,8 @@ Vertex::Vertex(Graph* parent, m_x=p.x(); m_y=p.y(); //FIXME outLinkColors list need update when we remove vertices/edges -// outLinkColors=new QString[1500]; - //Q_CHECK_PTR(outLinkColors); //outLinkColors.reserve(2000); + m_outEdgeLabels.reserve(100); m_outEdges.reserve(100); m_inEdges.reserve(100); m_outEdgesCounter=0; @@ -73,11 +72,10 @@ Vertex::Vertex(Graph* parent, m_SC=0; m_SSC=0; m_IRCC=0; m_SIRCC=0; m_CLC=0; m_hasCLC=false; m_curRelation=relation; - m_reciprocalLinked=false; m_enabled = true; connect (this, SIGNAL (setEdgeVisibility ( int, int, int, bool) ), - parent, SLOT (slotSetEdgeVisibility (int, int, int, bool)) ); + parent, SLOT (edgeVisibilitySet (int, int, int, bool)) ); } @@ -97,21 +95,20 @@ Vertex::Vertex(const long int &name) { m_DC=0; m_SDC=0; m_DP=0; m_SDP=0; m_CC=0; m_SCC=0; m_BC=0; m_SBC=0; m_IRCC=0; m_SIRCC=0; m_SC=0; m_SSC=0; m_curRelation=0; - m_reciprocalLinked=false; } /** -* @brief Vertex::changeRelation +* @brief Vertex::relationSet * @param relation */ -void Vertex::changeRelation(int relation) { - qDebug() << "Vertex::changeRelation() - Current: " << m_curRelation +void Vertex::relationSet(int relation) { + qDebug() << "Vertex::relationSet() - Current: " << m_curRelation << " new: " << relation; // first make false all edges of current relation - filterEdgesByRelation(m_curRelation, false); + edgeFilterByRelation(m_curRelation, false); // then make true all edges of new relation - filterEdgesByRelation(relation, true); + edgeFilterByRelation(relation, true); // update current relation m_curRelation=relation; } @@ -127,13 +124,13 @@ QString Vertex::colorToPajek(){ /** - * @brief Vertex::addEdgeTo + * @brief Vertex::edgeAddTo * Adds an outLink to target with weight w * @param target * @param weight */ -void Vertex::addEdgeTo (const long &v2, const float &weight) { - qDebug() <<"Vertex::addEdgeTo() - new link " +void Vertex::edgeAddTo (const long &v2, const float &weight) { + qDebug() <<"Vertex::edgeAddTo() - new link " << name() << " -> "<< v2 << " weight "<< weight << " relation " << m_curRelation; // do not use [] operator - silently creates an item if key do not exist @@ -178,12 +175,12 @@ void Vertex::setOutEdgeEnabled (long int target, bool status){ /** - * @brief Vertex::addEdgeFrom + * @brief Vertex::edgeAddFrom * @param source * @param weight */ -void Vertex::addEdgeFrom (const long int &v1, const float &weight) { -// qDebug() <<"Vertex: "<< name() << " addEdgeFrom() "<< source; +void Vertex::edgeAddFrom (const long int &v1, const float &weight) { +// qDebug() <<"Vertex: "<< name() << " edgeAddFrom() "<< source; m_inEdges.insertMulti( v1, rel_w_bool (m_curRelation, pair_f_b(weight, true) ) ); } @@ -214,81 +211,81 @@ void Vertex::changeOutEdgeWeight(long int target, float weight){ /** - * @brief Vertex::removeEdgeTo + * @brief Vertex::edgeRemoveTo * finds and removes a link to vertex v2 * @param v2 */ -void Vertex::removeEdgeTo (long int v2) { - qDebug() << "Vertex: removeEdgeTo() - vertex " << m_name +void Vertex::edgeRemoveTo (long int v2) { + qDebug() << "Vertex: edgeRemoveTo() - vertex " << m_name << " has " <0) { - qDebug () << "checking all_outEdges"; + qDebug() << "Vertex::edgeRemoveTo() - checking all_outEdges"; H_edges::iterator it1=m_outEdges.find(v2); while (it1 != m_outEdges.end() && it1.key() == v2 ) { if ( it1.value().first == m_curRelation ) { qDebug() << " *** vertex " << m_name << " connected to " << it1.key() << " relation " << it1.value().first << " weight " << it1.value().second.first - << " enabled ? " << it1.value().second.second; - qDebug() << " *** erasing outEdge from m_outEdges "; + << " enabled ? " << it1.value().second.second + << " Erasing outEdge from m_outEdges "; it1=m_outEdges.erase(it1); } else { ++it1; } } - qDebug() << "Vertex: vertex " << m_name << " now has " << outEdges() << " out-edges"; + qDebug() << "Vertex::edgeRemoveTo() - vertex " << m_name << " now has " << outEdges() << " out-edges"; } else { - qDebug() << "Vertex: vertex " << m_name << " has no edges" ; + qDebug() << "Vertex::edgeRemoveTo() - vertex " << m_name << " has no edges" ; } } /** - * @brief Vertex::removeEdgeFrom + * @brief Vertex::edgeRemoveFrom * @param v2 */ -void Vertex::removeEdgeFrom(long int v2){ - qDebug() << "Vertex: removeEdgeFrom() vertex " << m_name +void Vertex::edgeRemoveFrom(long int v2){ + qDebug() << "Vertex::edgeRemoveFrom() - vertex " << m_name << " has " << inEdges() << " in-edges. RemovingEdgeFrom " << v2 ; if (inEdges()>0) { - qDebug () << "checking all_inEdges"; + qDebug() << "Vertex::edgeRemoveFrom() - checking all_inEdges"; H_edges::iterator it=m_inEdges.find(v2); while (it != m_inEdges.end() ) { if ( it.key() == v2 && it.value().first == m_curRelation ) { qDebug() << " *** vertex " << m_name << " connected from " << it.key() << " relation " << it.value().first << " weight " << it.value().second.first - << " enabled ? " << it.value().second.second; - qDebug() << " *** erasing inEdge from m_inEdges "; + << " enabled ? " << it.value().second.second + << " Erasing inEdge from m_inEdges "; it=m_inEdges.erase(it); } else { ++it; } } - qDebug() << "Vertex: vertex " << m_name << " now has " + qDebug() << "Vertex::edgeRemoveFrom() - vertex " << m_name << " now has " << inEdges() << " in-links" ; } else { - qDebug() << "Vertex: vertex " << m_name << " has no edges"; + qDebug() << "Vertex::edgeRemoveFrom() - vertex " << m_name << " has no edges"; } } /** - * @brief Vertex::filterEdgesByWeight + * @brief Vertex::edgeFilterByWeight Called from Graph parent to filter edges over or under a specified weight (m_threshold) * @param m_threshold * @param overThreshold */ -void Vertex::filterEdgesByWeight(float m_threshold, bool overThreshold){ - qDebug() << "Vertex::filterEdgesByWeight of vertex " << this->m_name; +void Vertex::edgeFilterByWeight(float m_threshold, bool overThreshold){ + qDebug() << "Vertex::edgeFilterByWeight of vertex " << this->m_name; int target=0; float weight=0; QMutableHashIterator < int, rel_w_bool > it (m_outEdges); @@ -299,14 +296,14 @@ void Vertex::filterEdgesByWeight(float m_threshold, bool overThreshold){ weight = it.value().second.first; if (overThreshold) { if ( weight >= m_threshold ) { - qDebug() << "Vertex::filterEdgesByWeight(). Edge to " << target + qDebug() << "Vertex::edgeFilterByWeight() - edge to " << target << " has weight " << weight << ". It will be disabled. Emitting signal to Graph...."; it.setValue(rel_w_bool(m_curRelation, pair_f_b(weight, false) )); emit setEdgeVisibility (m_curRelation, m_name, target, false ); } else { - qDebug() << "Vertex::filterEdgesByWeight(). Edge to " << target + qDebug() << "Vertex::edgeFilterByWeight() - edge to " << target << " has weight " << weight << ". It will be enabled. Emitting signal to Graph...."; it.setValue(rel_w_bool(m_curRelation, pair_f_b(weight, true) )); emit setEdgeVisibility (m_curRelation, m_name, target, true ); @@ -314,13 +311,13 @@ void Vertex::filterEdgesByWeight(float m_threshold, bool overThreshold){ } else { if ( weight <= m_threshold ) { - qDebug() << "Vertex::filterEdgesByWeight(). Edge to " << target + qDebug() << "Vertex::edgeFilterByWeight() - edge to " << target << " has weight " << weight << ". It will be disabled. Emitting signal to Graph...."; it.setValue(rel_w_bool(m_curRelation, pair_f_b(weight, false) )); emit setEdgeVisibility (m_curRelation, m_name, target, false ); } else { - qDebug() << "Vertex::filterEdgesByWeight(). Edge to " << target + qDebug() << "Vertex::edgeFilterByWeight() - edge to " << target << " has weight " << weight << ". It will be enabled. Emitting signal to Graph...."; it.setValue(rel_w_bool(m_curRelation, pair_f_b(weight, true) )); emit setEdgeVisibility (m_curRelation, m_name, target, true ); @@ -335,12 +332,12 @@ void Vertex::filterEdgesByWeight(float m_threshold, bool overThreshold){ /** - * @brief Vertex::filterEdgesByRelation + * @brief Vertex::edgeFilterByRelation * Called from Graph to filter out all edges of a given relation * @param relation */ -void Vertex::filterEdgesByRelation(int relation, bool status ){ - qDebug() << "Vertex::filterEdgesByRelation() - Vertex " << this->m_name +void Vertex::edgeFilterByRelation(int relation, bool status ){ + qDebug() << "Vertex::edgeFilterByRelation() - Vertex " << this->m_name << " filtering edges of relation " << relation << " to " << status; int target=0; float weight =0; @@ -452,7 +449,7 @@ QHash* Vertex::returnReciprocalEdges(){ edgeStatus=it1.value().second.second; if ( edgeStatus == true) { m_weight=it1.value().second.first; - if (this->hasEdgeFrom (it1.key()) ) + if (this->hasEdgeFrom (it1.key()) == m_weight ) reciprocalEdges->insertMulti(it1.key(), m_weight); } } @@ -543,12 +540,12 @@ long int Vertex::inEdgesConst() const { /** - * @brief Vertex::outDegree - * Returns the outDegree (the sum of all enabled outEdges weights) of this vertex + * @brief Vertex::degreeOut + * Returns the degreeOut (the sum of all enabled outEdges weights) of this vertex * @return long int */ -long int Vertex::outDegree() { - qDebug() << "Vertex::outDegree()"; +long int Vertex::degreeOut() { + qDebug() << "Vertex::degreeOut()"; m_outDegree=0; float m_weight=0; int relation = 0; @@ -573,12 +570,12 @@ long int Vertex::outDegreeConst() { } /** - * @brief Vertex::inDegree - * Returns the inDegree (the sum of all enabled inEdges weights) of this vertex + * @brief Vertex::degreeIn + * Returns the degreeIn (the sum of all enabled inEdges weights) of this vertex * @return long int */ -long int Vertex::inDegree() { - qDebug() << "Vertex::inDegree()"; +long int Vertex::degreeIn() { + qDebug() << "Vertex::degreeIn()"; m_inDegree=0; float m_weight=0; int relation = 0; @@ -606,13 +603,13 @@ long int Vertex::inDegreeConst() { /** - localDegree is the outDegree + inDegree minus the edges counted twice. + localDegree is the degreeOut + degreeIn minus the edges counted twice. */ long int Vertex::localDegree(){ long int v2=0; int relation = 0; bool edgeStatus=false; - m_localDegree = (outDegree() + inDegree() ); + m_localDegree = (degreeOut() + degreeIn() ); H_edges::const_iterator it1=m_outEdges.constBegin(); while (it1 != m_outEdges.constEnd() ) { @@ -639,8 +636,7 @@ long int Vertex::localDegree(){ * @param v2 * @return */ -float Vertex::hasEdgeTo(long int v2){ -// qDebug()<< "Vertex::hasEdgeTo() " << name() << " -> " << v2 ; +float Vertex::hasEdgeTo(const long int &v2){ float m_weight=0; bool edgeStatus=false; H_edges::iterator it1=m_outEdges.find(v2); @@ -649,23 +645,20 @@ float Vertex::hasEdgeTo(long int v2){ edgeStatus=it1.value().second.second; if ( edgeStatus == true) { m_weight=it1.value().second.first; -// qDebug()<< "***** Vertex::hasEdgeTo() - relation " -// << it1.value().first -// <<" link " << this->name() -// << " -> " << v2 << "exists, weight "<< m_weight; + qDebug()<< "Vertex::hasEdgeTo() - a (" << this->name() + << ", " << v2 << ") = "<< m_weight; return m_weight; } else - qDebug()<< "Vertex::hasEdgeTo() - relation " - << it1.value().first - <<" link " << this->name() - << " -> " << v2 << "exists, weight "<< m_weight + qDebug()<< "Vertex::hasEdgeTo() - a (" << this->name() + << ", " << v2 << ") = "<< m_weight << " but edgeStatus " << edgeStatus; return 0; } ++it1; } - // qDebug()<< "Vertex::hasEdgeTo() - INEXISTENT LINK IN RELATION " << m_curRelation; +// qDebug()<< "Vertex::hasEdgeTo() - a (" << this->name() +// << ", " << v2 << ") = "<< m_weight; return 0; } @@ -677,8 +670,7 @@ float Vertex::hasEdgeTo(long int v2){ * @param v2 * @return */ -float Vertex::hasEdgeFrom(long int v2){ - qDebug()<< "Vertex::hasEdgeFrom()" ; +float Vertex::hasEdgeFrom(const long int &v2){ float m_weight=0; bool edgeStatus=false; H_edges::iterator it1=m_inEdges.find(v2); @@ -687,20 +679,20 @@ float Vertex::hasEdgeFrom(long int v2){ edgeStatus=it1.value().second.second; if ( edgeStatus == true) { m_weight=it1.value().second.first; - qDebug()<< "Vertex::hasEdgeFrom() - a (" << this->name() - << ", " << v2 << ") = "<< m_weight; + qDebug()<< "Vertex::hasEdgeFrom() - a (" << v2 + << ", " << this->name() << ") = "<< m_weight; return m_weight; } else - qDebug()<< "Vertex::hasEdgeFrom() - a (" << this->name() - << ", " << v2 << ") = "<< m_weight + qDebug()<< "Vertex::hasEdgeFrom() - a (" << v2 + << ", " << this->name() << ") = "<< m_weight << " but edgeStatus " << edgeStatus; return 0; } ++it1; } - qDebug()<< "Vertex::hasEdgeFrom() - a (" << this->name() << ", " << v2 << ") = 0 "; + //qDebug()<< "Vertex::hasEdgeFrom() - a (" << this->name() << ", " << v2 << ") = 0 "; return 0; } @@ -717,7 +709,7 @@ int Vertex::cliques (const int &size) return count ; } -bool Vertex::addClique (const QString &clique, const int &size) { +bool Vertex::cliqueAdd (const QString &clique, const int &size) { QStringList members = clique.split(","); switch (size) { case 2: @@ -801,6 +793,7 @@ Vertex::~Vertex() { qDebug() << " Vertex:: destroying my data"; m_outEdges.clear(); outLinkColors.clear(); + m_outEdgeLabels.clear(); clearPs(); m_outEdges.clear(); m_inEdges.clear(); diff --git a/src/vertex.h b/src/vertex.h index 043fe329..234ad067 100755 --- a/src/vertex.h +++ b/src/vertex.h @@ -5,7 +5,7 @@ vertex.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -78,17 +78,17 @@ class Vertex : public QObject{ void setEnabled (const bool &flag ) { m_enabled=flag; } bool isEnabled () const { return m_enabled; } - void changeRelation(int) ; + void relationSet(int) ; - void addEdgeTo (const long int &v2, const float &weight); - void addEdgeFrom(const long int &v1, const float &weight); + void edgeAddTo (const long int &v2, const float &weight); + void edgeAddFrom(const long int &v1, const float &weight); void changeOutEdgeWeight (long int target, float weight); void setOutEdgeEnabled (long int, bool); - void removeEdgeTo (long int target); - void removeEdgeFrom(long int source); + void edgeRemoveTo (long int target); + void edgeRemoveFrom(long int source); QHash* returnEnabledOutEdges(); QHash* returnReciprocalEdges(); @@ -99,9 +99,9 @@ class Vertex : public QObject{ long int inEdges(); long int inEdgesConst() const ; - long int outDegree(); + long int degreeOut(); long int outDegreeConst(); - long int inDegree(); + long int degreeIn(); long int inDegreeConst(); long int localDegree(); @@ -109,25 +109,21 @@ class Vertex : public QObject{ void setEccentricity (float c){ m_Eccentricity=c;} float eccentricity() { return m_Eccentricity;} - /* Returns true if there is a reciprocal link from this vertex */ - bool isReciprocalLinked() { return m_reciprocalLinked;} - void setReciprocalLinked(bool reciprocal) { m_reciprocalLinked=reciprocal;} - /* Returns true if there is an outLink from this vertex */ bool isOutLinked() { return (outEdges() > 0) ? true:false;} /* Returns the weight of the link to vertex V, otherwise zero*/ - float hasEdgeTo(long int V); + float hasEdgeTo(const long int &v); /* Returns true if there is an outLink from this vertex */ bool isInLinked() { return (inEdges() > 0) ? true:false;} - float hasEdgeFrom (long int v); + float hasEdgeFrom (const long int &v); bool isIsolated() { return !(isOutLinked() | isInLinked()) ; } void setIsolated(bool isolated) {m_isolated = isolated; } - void filterEdgesByWeight(float m_threshold, bool overThreshold); + void edgeFilterByWeight(float m_threshold, bool overThreshold); // void filterEdgesByColor(float m_threshold, bool overThreshold); - void filterEdgesByRelation(int relation, bool status); + void edgeFilterByRelation(int relation, bool status); void setSize(const int &size ) { m_size=size; } int size() const { return m_size; } @@ -145,15 +141,21 @@ class Vertex : public QObject{ void setNumberSize (const int &size) { m_numberSize=size; } int numberSize() const { return m_numberSize; } + void setNumberDistance (const int &distance) { m_numberDistance=distance; } + int numberDistance() const { return m_numberDistance; } + void setLabel (const QString &label) { m_label=label; } QString label() const { return m_label; } void setLabelColor (const QString &labelColor) { m_labelColor=labelColor; } QString labelColor() const { return m_labelColor; } - void setLabelSize(const int &newSize) { m_labelSize=newSize; } + void setLabelSize(const int &size) { m_labelSize=size; } int labelSize() const { return m_labelSize; } + void setLabelDistance (const int &distance) { m_labelDistance=distance; } + int labelDistance() const { return m_labelDistance; } + void setX(const float &x) { m_x=x; } float x() const { return m_x; } @@ -169,9 +171,9 @@ class Vertex : public QObject{ void set_dispY (float y) { m_disp.ry() = y ; } //FIXME -- VERY SLOW? - void setOutLinkColor(const long int &v2, const QString &color) { - outLinkColors[v2]=color; - } + void setOutLinkColor(const long int &v2, + const QString &color) { outLinkColors[v2]=color; } + //FIXME: See MW line 1965 - FIXME MULTIGRAPH QString outLinkColor(const long int &v2) { if (outLinkColors.contains(v2)) @@ -179,6 +181,16 @@ class Vertex : public QObject{ else return "black"; } + + void setOutEdgeLabel(const long int &v2, + const QString &label) { m_outEdgeLabels[v2]=label; } + QString outEdgeLabel(const long int &v2) const { + if (m_outEdgeLabels.contains(v2)) + return m_outEdgeLabels.value(v2); + else return QString::null; + } + + void setDelta (float c){ m_delta=c;} /* Sets vertex pair dependancy */ float delta() { return m_delta;} /* Returns vertex pair dependancy */ @@ -249,7 +261,7 @@ class Vertex : public QObject{ int cliques (const int &size); - bool addClique (const QString &clique, const int &size); + bool cliqueAdd (const QString &clique, const int &size); void clearCliques() { m_cliques.clear(); @@ -268,13 +280,13 @@ class Vertex : public QObject{ ilist myPs; long int m_name, m_outEdgesCounter, m_inEdgesCounter, m_outDegree, m_inDegree, m_localDegree; float m_Eccentricity; - int m_value, m_size, m_labelSize, m_numberSize, m_curRelation; + int m_value, m_size, m_labelSize, m_numberSize, m_numberDistance, m_labelDistance; + int m_curRelation; H_StrToInt m_cliques; bool m_reciprocalLinked, m_enabled, m_hasCLC, m_isolated; QString m_color, m_numberColor, m_label, m_labelColor, m_shape; QPointF m_disp; - //QString *outLinkColors; - H_IntToStr outLinkColors; + H_IntToStr outLinkColors, m_outEdgeLabels; //FIXME vertex coords double m_x, m_y; diff --git a/src/webcrawler.cpp b/src/webcrawler.cpp index ec205a27..36542603 100755 --- a/src/webcrawler.cpp +++ b/src/webcrawler.cpp @@ -5,7 +5,7 @@ webcrawler.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ diff --git a/src/webcrawler.h b/src/webcrawler.h index 63d99aa2..23250c07 100755 --- a/src/webcrawler.h +++ b/src/webcrawler.h @@ -5,7 +5,7 @@ webcrawler.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ @@ -47,8 +47,8 @@ public slots: void parse(QNetworkReply *reply); void newLink(int s, QUrl target, bool enqueue_to_frontier); signals: - void signalCreateNode(QString url, int no); - void signalCreateEdge (int source, int target); + void signalCreateNode(const QString &url, const int &no); + void signalCreateEdge (const int &source, const int &target); void startSpider(); void finished (QString); private: diff --git a/src/webcrawlerdialog.cpp b/src/webcrawlerdialog.cpp index ba6b7285..d36a0714 100755 --- a/src/webcrawlerdialog.cpp +++ b/src/webcrawlerdialog.cpp @@ -5,7 +5,7 @@ webcrawlerdialog.cpp - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com ***************************************************************************/ diff --git a/src/webcrawlerdialog.h b/src/webcrawlerdialog.h index 658b88b5..3ae5cd1e 100755 --- a/src/webcrawlerdialog.h +++ b/src/webcrawlerdialog.h @@ -5,7 +5,7 @@ webcrawlerdialog.h - description ------------------- - copyright : (C) 2005-2015 by Dimitris B. Kalamaras + copyright : (C) 2005-2016 by Dimitris B. Kalamaras email : dimitris.kalamaras@gmail.com website: : http://dimitris.apeiro.gr project site : http://socnetv.sourceforge.net