summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--doc/LaTeX/bilder/processlist.pngbin0 -> 82069 bytes
-rw-r--r--doc/LaTeX/bilder/runprocess.pngbin0 -> 41192 bytes
-rw-r--r--doc/LaTeX/devel/0300-pvs.tex46
-rw-r--r--doc/LaTeX/devel/0400-pvs-console.tex97
-rw-r--r--doc/LaTeX/intro/0000-chapter.tex4
-rw-r--r--doc/LaTeX/intro/0100-funktionen.tex2
-rw-r--r--doc/LaTeX/user/0001-chapter.tex40
-rw-r--r--misc/pvs.conf3
-rw-r--r--src/core/pvsConnectionManager.cpp76
-rw-r--r--src/gui/mainWindow.cpp74
-rw-r--r--src/gui/mainWindow.h11
-rw-r--r--src/gui/processWidget.cpp72
-rw-r--r--src/gui/processWidget.h5
-rw-r--r--src/gui/processesDialog.cpp39
-rw-r--r--src/gui/processesDialog.h4
-rw-r--r--src/gui/processesStartDialog.cpp142
-rw-r--r--src/gui/processesStartDialog.h21
-rw-r--r--src/gui/ui/mainwindow.ui5
-rw-r--r--src/gui/ui/mainwindowtouch.ui9
-rw-r--r--src/gui/ui/processWidget.ui12
-rw-r--r--src/gui/ui/processesDialog.ui2
-rw-r--r--src/gui/ui/processesStartDialog.ui193
-rwxr-xr-xsrc/pvs.cpp70
-rwxr-xr-xsrc/pvs.h3
25 files changed, 671 insertions, 261 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4eeaea8..dbbdeb0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -159,6 +159,7 @@ SET( PVSMGR_UIS
src/gui/ui/aboutDialog.ui
src/gui/ui/serverChatDialog.ui
src/gui/ui/clientFileSendDialog.ui
+ src/gui/ui/processesStartDialog.ui
src/gui/ui/processesDialog.ui
src/gui/ui/processWidget.ui
src/gui/ui/multicastConfigDialog.ui
@@ -220,6 +221,7 @@ SET( PVSMGR_MOC_HDRS
src/net/pvsServiceBroadcast.h
src/net/SslServer.h
src/gui/aboutDialog.h
+ src/gui/processesStartDialog.h
src/gui/processesDialog.h
src/gui/processWidget.h
src/gui/multicastConfigDialog.h
diff --git a/doc/LaTeX/bilder/processlist.png b/doc/LaTeX/bilder/processlist.png
new file mode 100644
index 0000000..c2e09af
--- /dev/null
+++ b/doc/LaTeX/bilder/processlist.png
Binary files differ
diff --git a/doc/LaTeX/bilder/runprocess.png b/doc/LaTeX/bilder/runprocess.png
new file mode 100644
index 0000000..7b2f6bd
--- /dev/null
+++ b/doc/LaTeX/bilder/runprocess.png
Binary files differ
diff --git a/doc/LaTeX/devel/0300-pvs.tex b/doc/LaTeX/devel/0300-pvs.tex
index 4978571..0060a63 100644
--- a/doc/LaTeX/devel/0300-pvs.tex
+++ b/doc/LaTeX/devel/0300-pvs.tex
@@ -1,10 +1,11 @@
\chapter{Aufbau und Funktionsweise des PVS}
\index{Aufbau} \index{Funktionsweise} \index{Konzept}
-Generelles Konzept
+Der Pool Video Switch ist als verteilte Netzwerkapplikation angelegt, die sich aus einer speziellen Steuerkonsole und damit gesteuerten Clients zusammensetzt. Diese kommunizieren untereinander einerseits über ein spezielles Message-Protokoll, verwenden andererseits für bestimmte Aufgaben, wie die Übertragung von Bildinhalten oder Dateien weitere Protokolle wie VNC oder Multicast-IP.
\section{Einzelne Komponenten}
\index{Komponenten}
+Die Steuerkonsole wird durch das Programm pvsmgr, das Client-Backend durch pvs und das Client-Frontend durch pvsgui repräsentiert.
\subsection{Zuordnung von Konsole und Clients}
\input{devel/0310-service-discovery}
@@ -393,6 +394,27 @@ in Präprozessorbedingungen geschehen.
Eine API-Referenz zur libpvsinput (Stand: 4.~November~2010) findet sich im Projektwiki
unter \url{http://lab.openslx.org/projects/pvs/wiki/RemoteKeyMouse}.
+\section{Prozesse fernsteuern}
+\index{Prozesse fernsteuern}
+
+\subsection{Prozesse starten}
+\index{Prozesse!starten} \index{starten}
+Das ferngesteuerte Starten von Prozessen funktioniert durch den einfachen Versand eines PVSCOMMAND mit dem dem Ident STARTPROCESS an den Client, der Inhalt des PVSCOMMAND ist in diesem Fall ein durch den Dozenten angegebener Prozess. Der Client versucht diesen Prozess lokal zu starten.\\
+Sollte hierbei ein Fehler auftreten schickt der Client dem Manager ein PVSCOMMAND mit Ident PROCESSES, der Inhalt besteht dann aus der Nachricht START ERROR und einer Zahl, die die Art des Fehlers angibt.\\
+Die Fehlermeldung wird zusammen mit der Information über die Art des Fehlers (Fehlender Prozess/nicht genug Rechte, Crash, Timeout, Read Error, Write Error, Unbekannter Fehler) im Log angezeigt.
+
+\subsection{Prozesse beenden}
+\index{Prozesse!beenden} \index{beenden}
+Das ferngesteuerte Beenden von Prozessen funktioniert analog zum Starten durch den Versand eines PVSCOMMAND mit dem dem Ident KILLPROCESS an den Client, hier gibt der Inhalt die lokale PID, des zu beendenden Prozesses an.\\
+Auch hier schickt der Client dem Manager bei einem Fehler ein PVSCOMMAND mit Ident PROCESSES, der Inhalt besteht dann aus der Nachricht STOP ERROR und einer Zahl, die die Art des Fehlers angibt.\\
+Auch hier wird die Fehlermeldung zusammen mit der Information über die Art des Fehlers (Fehlender Prozess/nicht genug Rechte, Crash, Timeout, Read Error, Write Error, Unbekannter Fehler) im Log angezeigt.
+
+\subsection{Prozesseliste anzeigen}
+\index{Prozesse!anzeigen} \index{anzeigen}
+Hier sendet der Manager dem Client ein PVSCOMMAND mit Ident SHOWPROCESSES. Das PVSCOMMAND mit Ident SHOW und Inhalt clear lässt den Client seine Prozessliste leeren.\\
+Anschließend wird der Inhalt von \textit{/proc/} auf dem Client ausgelesen, ist kein Inhalt vorhanden wird ein PVSCOMMAND mit Ident PROCESSES und Nachricht SHOW ERROR gesendet. Sonst werden sämtliche Ordner in \textit{/proc/} die nur aus Zahlen bestehen durchlaufen. Es wird die Datei \textit{status} ausgelesen um den Namen des Prozesses und die UID des Besitzers zu erhalten. Ist die UID nicht identisch mit der UID des Client wird dieser Prozess verworfen, somit ist sichergestellt, dass nur Prozesse angezeigt werden, bei denen auch tatsächlich die Berechtigung vorhanden ist sie zu beenden. Ist dies der Fall wird außerdem noch ein Teil der Datei \textit{cmdline} ausgelesen. Der Client sendet daraufhin ein PVSCOMMAND mit Ident SHOW und Inhalt PID<\#>Name<\#>cmdline und füllt somit seinen Prozessvektor auf. Ist \textit{/proc} komplett abgearbeitet wird ein PVSCOMMAND mit Ident SHOW und Inhalt finished abgesendet, dies löst ein erneuetes lesen der Prozessliste Managerseitig aus:\\
+Hier wird zu beginn die Prozessliste des Client gelöscht und der Prozessvektor des Clients gelesen. Für jeden Eintrag der Art PID<\#>Name<\#>cmdline wird eine neue Zeile in der Prozessliste geschrieben und PID, Name und cmdline in die jeweiligen Zellen geschrieben.
+
\section{Netzwerkkommunikation}
\index{Netzwerkkommunikation}
@@ -421,6 +443,9 @@ PVSCOMMAND & UNPROJECT & & \\
PVSCOMMAND & LOCKSTATION & & \\
PVSCOMMAND & LOCKSTATION & Message & Client mit Nachricht sperren \\
PVSCOMMAND & UNLOCKSTATION & & \\
+PVSCOMMAND & STARTPROCESS & process & gibt Prozessnamen an der auf Client gestartet werden soll\\
+PVSCOMMAND & KILLPROCESS & PID & gibt ProzessID an von Prozess der auf Client beendet werden soll\\
+PVSCOMMAND & SHOWPROCESSES & & weist den Client an seine Prozesse auszulesen und den Prozessvektor zu füllen\\
PVSLOGIN & USERNAME & username & Client Benutzername \\
PVSLOGIN & PASSWORD & password & Serverpasswort \\
PVSLOGIN & ID & id & \\
@@ -435,14 +460,31 @@ PVSCOMMAND & VNCREQUEST & & \\
PVSCOMMAND & VNCSRVRESULT & result code & Der Rückgabewert des pvs-vncsrv Skripts \\
PVSCOMMAND & MCASTFTANNOUNCE & sender transferID basename size port & Ankündigung eines Multicast-Transfer \\
PVSCOMMAND & MCASTFTRETRY & sender transferID & Rückmeldung: Konfiguration des Multicast-Empfängers fehlgeschlagen, bitte auf anderem Port noch einmal versuchen \\
+\end{tabular}
+\end{center}
+\caption{Liste der PVS Messages}
+\label{tab:messagelist}
+\end{table}
+
+\begin{table}
+\begin{center}
+\begin{tabular}{l | l | p{2cm} | p{4cm}}
+\label{pvs-msg-liste}
+Nachrichtentyp & Nachrichten Ident & Inhalt & Beschreibung \\
+\hline
PVSCOMMAND & MCASTFTCONFIG & blob & Multicast-Konfiguration aus dem angehängten Binärblob neu laden \\
PVSCOMMAND & INPUTEVENT & Base64-kodierte InputEvent-Struktur & Fernsteuerung \\
+PVSCOMMAND & PROCESSES & START ERROR errorlevel & errorlevel gibt an, welcher Fehler beim Starten eines Prozesses aufgetreten ist \\
+PVSCOMMAND & PROCESSES & STOP ERROR errorlevel & errorlevel gibt an, welcher Fehler beim Beenden eines Prozesses aufgetreten ist \\
+PVSCOMMAND & PROCESSES & SHOW ERROR & gibt an, dass beim Anzeigen der Prozessliste ein Fehler aufgetreten ist \\
+PVSCOMMAND & PROCESSES & SHOW clear & weist Client an den Prozessvektor zu leeren \\
+PVSCOMMAND & PROCESSES & SHOW finished & weist Manager an, Prozessliste neu zu füllen \\
PVSMESSAGE & BROADCAST & MESSAGE &\\
PVSMESSAGE & clientToAdd & & Client hinzufügen (Chat)\\
PVSMESSAGE & clientToRemove & & Client entfernen (Chat)\\
PVSMESSAGE & assignedName & & Festgelegter Name (Chat)\\
\end{tabular}
\end{center}
-\caption{Liste der PVS Messages}
+\caption{Liste der PVS Messages (Fortsetzung}
\label{tab:messagelist}
\end{table}
diff --git a/doc/LaTeX/devel/0400-pvs-console.tex b/doc/LaTeX/devel/0400-pvs-console.tex
index d9b1ca0..78574b2 100644
--- a/doc/LaTeX/devel/0400-pvs-console.tex
+++ b/doc/LaTeX/devel/0400-pvs-console.tex
@@ -1,25 +1,24 @@
\chapter{PVS-Steuerkonsole}
Die Steuerkonsole ist das Hauptquartier des \textbf{Pool Video Switch}. Sie wird auf der Dozentmaschine oder
-einer geeigneten weiteren Maschine ausgef{\"u}hrt und sie ist für die Steuerung der Clients-Maschine zuständig.
+einer geeigneten weiteren Maschine ausgeführt und sie ist für die Steuerung der Clients-Maschine zuständig.
Alleine diese Rolle der Steuerkonsole setzt schon voraus, dass das GUI so benutzerfreundlich aufgebaut werden soll,
dass diese Aufgabe vereinfacht wird.~\\
-Wir werden uns in den n{\"a}chsten Punkten auf den technischen Aufbau der Steuerkonsole fokussieren.
+Wir werden uns in den nächsten Punkten auf den technischen Aufbau der Steuerkonsole fokussieren.
Wir werden als erstes die Auswahl von Qt zum Aufbau des Server-GUI, dann werden wir die GUI Server-Konsole vorstellen und zum
Schluss werden wir die Beziehung Server-Client unter die Lupe nehmen.
\section{pvsmgr in Qt}
-Das Server-GUI wurde erstmal in GTK/Gnome implementiert. Dank der Flexibilit{\"a}t, die von Qt erm{\"o}glicht wird, wurde die komplette
-Anwendung in Qt umgeschrieben. Qt ist ein UI Framework und ermöglicht die Implementierung von Anwendungen, die unter Linux (Unix),
-Windows, mobile und eingebettete Systemen ausf{\"u}hrbar sind. Wir werden also den pvs-Manager(Server-GUI) komplett in Qt umschreiben und mit
-zus{\"a}tzlichen Features gestalten.
+Das Server-GUI wurde in der ersten Version in GTK/Gnome implementiert. Dank der Flexibilität, die von Qt ermöglicht wird, wurde die komplette
+Anwendung in Qt umgeschrieben. Qt ist ein User Interface Framework und ermöglicht die Implementierung von Anwendungen, die unter Linux (Unix), Windows, mobile und eingebettete Systemen ausführbar sind.
\section{GUI Server-Konsole}
Hier sollte die Hauptsteuerung des PVS abgewickelt werden.
-\subsection{Die Architektur}
-Es wird u.a. m{\"o}glich sein, Funktionen auszuführen wie: die Frame der einzelnen Clients ansehen, ein Profil anlegen,
-Screenshot aufnehmen, ein (Un)Projektion ausf{\"u}hren, eine Nachricht an Clients verschicken, usw... Die Grundstruktur
+
+\subsection{Architektur}
+Es wird u.a. möglich sein, Funktionen auszuführen wie: die Frame der einzelnen Clients ansehen, ein Profil anlegen,
+Screenshot aufnehmen, ein (Un)Projektion ausführen, eine Nachricht an Clients verschicken, usw... Die Grundstruktur
des pvsmgr wird in der Abbildung \ref{fig:pvsmgr} illustriert. Das Bild zeigt uns das Hauptfenster (\textit{MainWindow})
der Anwendung und seine unterschiedlichen Komponenten:~\\ ~\\ ~\\ ~\\ ~\\
\begin{figure}[h]
@@ -30,48 +29,48 @@ der Anwendung und seine unterschiedlichen Komponenten:~\\ ~\\ ~\\ ~\\ ~\\
\end{figure}
\textbf{MainWindow}~\\
Die Klasse MainWindow wird vom QMainWindow abgeleitet; das ist der Parent an der Spitze der Hierachie;
-Sie zu zerst{\"o}ren, bedeutet ein automatisches
+Sie zu zerstören, bedeutet ein automatisches
Schließen der einzelnen Komponente, also der gesammten Anwendung. Alle anderen Komponenten bauen auf ihr auf.
-Die Abbildung \ref{fig:mainwindow} zeigt ihr Abh{\"a}ngigkeitsdiagramm.
+Die Abbildung \ref{fig:mainwindow} zeigt ihr Abhängigkeitsdiagramm.
~\\
Alle andere Komponenten (Klasse) der Anwendung haben die Klasse MainWindow als Parent. Qt verwaltet eine Struktur der
-Art \textit{parent-child} Beziehung, so dass wenn ein Parent zerst{\"o}rt wird, werden alle seine Kinder (\textit{child})
-automatisch mit zers{\"o}rt; Das ist der sogenannte \textit{Domino-Effekt}.
+Art \textit{parent-child} Beziehung, so dass wenn ein Parent zerstört wird, werden alle seine Kinder (\textit{child})
+automatisch mit zersört; Das ist der sogenannte \textit{Domino-Effekt}.
~\\
\begin{figure}[h]
\centering
\includegraphics[width=0.80\textwidth]{bilder/mainwindow.png}
- \caption{Abh{\"a}ngigkeitsdiagram: MainWindow}
+ \caption{Abhängigkeitsdiagram: MainWindow}
\label{fig:mainwindow}
\end{figure}
-~\\
+
\textbf{Menubar}~\\
-Diese Klasse enth{\"a}lt eine Liste von \textit{pull-down}-Menu und QMainWindow speichert diese im QMenuBar. Die Klasse
-wird also vom QMenuBar abgeleitet. Die gespeicherten Men{\"u}s enthalten jeweils die Menu-Items, die nichts anderes als \textit{QAction} sind.
+Diese Klasse enthält eine Liste von \textit{pull-down}-Menu und QMainWindow speichert diese im QMenuBar. Die Klasse
+wird also vom QMenuBar abgeleitet. Die gespeicherten Menüs enthalten jeweils die Menu-Items, die nichts anderes als \textit{QAction} sind.
Beim Betätigen einer Aktion (Menü-Item) wird ein korrespondiertes \textit{SIGNAL} gesendet, wir verbinden dann dieses zu einem \textit{SLOTS},
wie hier gezeigt wird \textit{connect(actionCreate-profile, SIGNAL(triggered()), MainWindow, SLOT(createProfile()))}; Also beim Clicken auf das Menü-Item
"File->Profile manager" wird das Signal \textit{triggered()} gesendet, das automatisch das Slot \textit{createProfile()} aufruft. Genau dieses Prinzip
-wird auch auf die Aktionen im Toolbar angewandt. ~\\
+wird auch auf die Aktionen im Toolbar angewandt.
\textbf{Toolbar}~\\
-Die Klasse wird vom QToolBatr abgeleitet und enth{\"a}lt eine Liste von Aktionen, die man unmittelbar auf die gesamten
-oder die ausgew{\"a}hlten Clients in der ConnectionList anwenden kann. ~\\ ~\\
+Die Klasse wird vom QToolBatr abgeleitet und enthält eine Liste von Aktionen, die man unmittelbar auf die gesamten
+oder die ausgewählten Clients in der ConnectionList anwenden kann. ~\\ ~\\
\textbf{ConnectionList}~\\
-Sie enth{\"a}lt die Liste der verbundenen Clients. Sie ist vom QTableView abgeleitet. Die vorhandenen Clients in der Liste k{\"o}nnen
-in unterschiedlichen Bezeichnungen angezeigt werden. Es ist also m{\"o}glich die Clients unter verschiedenen Sichten anzuzeigen.
-Die Clients k{\"o}nnen mit Name, IP-Adresse oder Username angezeigt werden. Wir entnehmen also, dass das QTableView genauer gesehen
-3 Spalten enth{\"a}lt, von denen nur eins davon immer sichtbar wird. Dieses Geschehen l{\"a}sst sich ganz trivial ausführen.
- Man soll lediglich daf{\"u}r sorgen, dass wenn eine Spalte angezeigt wird, sollen die 2 anderen ausgeblendet werden.
+Sie enthält die Liste der verbundenen Clients. Sie ist vom QTableView abgeleitet. Die vorhandenen Clients in der Liste können
+in unterschiedlichen Bezeichnungen angezeigt werden. Es ist also möglich die Clients unter verschiedenen Sichten anzuzeigen.
+Die Clients können mit Name, IP-Adresse oder Username angezeigt werden. Wir entnehmen also, dass das QTableView genauer gesehen
+3 Spalten enthält, von denen nur eins davon immer sichtbar wird. Dieses Geschehen lässt sich ganz trivial ausführen.
+ Man soll lediglich dafür sorgen, dass wenn eine Spalte angezeigt wird, sollen die 2 anderen ausgeblendet werden.
Das QTableView steht zu diesem Zweck die Methode \textit{setColumnHidden(int column, bool hidden)} zur Verfügung, wobei \textit{column}
die betroffene Spaltenummer (die erste Spalte hat den Index 0) ist und \textit{hidden} legt dann fest, ob die Spalte
ein-(\textit{true}) oder ausgeblendet(\textit{false}) bleiben soll. Angesichts des angewandten Selection-Model
(\textit{QItemSelectionModel}) ist es möglich mehrere Clients (\textit{QAbstractItemView::ExtendedSelection}) aufzufassen und
-die entsprechenden verfügbaren Aktionen aus dem Tollbar oder der ContexMenu auszuf{\"u}hren.~\\
+die entsprechenden verfügbaren Aktionen aus dem Tollbar oder der ContexMenu auszuführen.~\\
\textbf{ConnectionWindow}~\\
-Die Klasse ist wie der zentrale Widget der Anwendung. Sie ist vom QWidget abgeleitet und enth{\"a}lt die Frame der
+Die Klasse ist wie der zentrale Widget der Anwendung. Sie ist vom QWidget abgeleitet und enthält die Frame der
jeweiligen verbundenen Clients. Klarerweise hat diese Komponente die MainWindow-Klasse als Parent.~\\
\textbf{ConsoleLog}~\\
@@ -84,15 +83,15 @@ Die richtig konfigurierten Clients werden mit dem pvs-Server verbunden und werde
\subsubsection{Clientliste-Ansicht}
Diese Sicht ist eine Liste, die aus einem \textit{QTableview}-Object abgeleitet wird. Die Client-Liste ist definiert
-durch die ConnectionList-Klasse die Abbildung \ref{fig:connectionlist} zeigt uns die Abh{\"a}ngigkeitsdiagramm dieser Klasse.
+durch die ConnectionList-Klasse die Abbildung \ref{fig:connectionlist} zeigt uns die Abhängigkeitsdiagramm dieser Klasse.
\begin{figure}[h]
\centering
\includegraphics[width=0.80\textwidth]{bilder/ConnectionList.png}
- \caption{Abh{\"a}ngigkeitsdiagramm der ConnectionList-Klasse}
+ \caption{Abhängigkeitsdiagramm der ConnectionList-Klasse}
\label{fig:ConnectionList}
\end{figure}
-Die Tabelle enth{\"a}lt 3 Spalten, von denen nur eine angezeigt werden kann. Mit Hilfe passender Tastenkombinationen
+Die Tabelle enthält 3 Spalten, von denen nur eine angezeigt werden kann. Mit Hilfe passender Tastenkombinationen
können die anderen Spalten angezeigt werden. Die Spalten enthalten jeweils den Name der Clients, seine IP-Adresse und seinen Username. Außerdem
haben wir hier ein Kontextmenü per Überschreibung der Methode \textit{mouseReleaseEvent(QMouseEvent * e)} aus der Mutter-Klasse (QTableView)
zur Verfügung gestellt. Das Kontextmenü ist hier im Grunde ein Popup-Menü, das Menü-Item enthält. Diese Menü-Items sind nichts anderes als Actionen
@@ -102,7 +101,7 @@ Von der jeweiligen Clients in der ConnectionList wollen wir jetzt die entspreche
\subsubsection{VNC-Ansicht}
-Die zweite Anzeigem{\"o}glichkeit, die vom Server angeboten wird ist die Anzeige der VNC-Verbindung zwischen
+Die zweite Anzeigemöglichkeit, die vom Server angeboten wird ist die Anzeige der VNC-Verbindung zwischen
Client und Server. Genauer gesagt, auf dem pvsmgr kann der Dozent jeder Zeit nachvollziehen, was auf der Client-Maschine
passiert, dies wird vom rfb (Remote Frame Buffer) ermöglicht. Zu dem jeweiligen Client wird vom Manager ein \textit{VNCClientThread()} initialisiert
und in dieser Klasse wird der rfb-Client instanziiert. Die Klasse\textit{VNCClientThread()} wird vom QThread abgeleitet, somit wird eine kontinuierliche
@@ -114,7 +113,7 @@ Quality zu starten und danach dem Client diesen neuen Thread wieder zuzuordnen.~
\begin{figure}[h]
\centering
\includegraphics[width=0.80\textwidth]{bilder/connectionframe.png}
- \caption{Abh{\"a}ngigkeitsdiagramm der ConnectionFrame-Klasse}
+ \caption{Abhängigkeitsdiagramm der ConnectionFrame-Klasse}
\label{fig:Connectionframe}
\end{figure}
Die VNC-Ströme werden in der ConnectionFrame-Klasse verwaltet. Die ConnectionFrame ist vom QGroupBox abgeleitet. Die Abbildung \ref{connectionframe}
@@ -128,39 +127,37 @@ annähen, in dem wir dieser Aushandlung diese Verbindung betrachten. Allerdings
\subsection{Client-Seite}
Wir wollen davon ausgehen, dass im Subnetz, indem sich die Client-Maschine befindet, bereits ein pvsmgr gestartet wurde.
- Die Abwicklung auf dem server werden wir im n{\"a}chsten Punkt erl{\"a}utern. Nach dem Start eines Server sendet dieser eine
-Broadcast-Nachricht, die von allen verf{\"u}gbaren Client erhalten wird. Erh{\"a}lt ein Client diese Nachricht, dann weiß er,
-dass ein Server gerade am laufen ist. Anschließend f{\"u}gt der Client diesen Server in seiner Server-Liste hinzu.
+ Die Abwicklung auf dem server werden wir im nächsten Punkt erläutern. Nach dem Start eines Server sendet dieser eine
+Broadcast-Nachricht, die von allen verfügbaren Client erhalten wird. Erhält ein Client diese Nachricht, dann weiß er,
+dass ein Server gerade am laufen ist. Anschließend fügt der Client diesen Server in seiner Server-Liste hinzu.
Wird es eine von einen anderen Server gesendetete Broadcast-Nachricht empfangen, wird ebenfalls den entsprechenden
Server in die Server-Liste des Client hinzugenommen.
-Der Client verf{\"u}gt also {\"u}ber eine Liste von potentiellen Server, mit denen er eine PVS-Verbindung aufbauen kann, die dann schließlich
+Der Client verfügt also über eine Liste von potentiellen Server, mit denen er eine PVS-Verbindung aufbauen kann, die dann schließlich
eine VNC-Verbindung wird und erst dann kann die Remote Frame Buffer initialisiert werden. Verläuft diese Initiliasierung erfolgreich, wird bei dem Server
der VNC-Frame angezeigt.
-Aus seiner Server-Liste kann der Client freiwillig den Server ausw{\"a}hlen, mit dem er sich verbinden m{\"o}chte. Allerdings
+Aus seiner Server-Liste kann der Client freiwillig den Server auswählen, mit dem er sich verbinden möchte. Allerdings
erfolgt die eigentliche Verbindung zwischen Server und Client erst, nachdem der Client das vom Dozent gesetzte Passwort
-richtig eingegeben hat. Beim Start des Server wird vom System ein zuf{\"a}lliges Passwort generiert und der Dozent soll dieses den Client
+richtig eingegeben hat. Beim Start des Server wird vom System ein zufälliges Passwort generiert und der Dozent soll dieses den Client
im Raum bekanntgegeben, so dass ein anderer Client, der im Nebenraum steht und auch die Server-Broadcast-Nachricht erhalten hat,
-keine M{\"0}glichkeit hat, mit diesem Server eine Verbindung aufbauen zu k{\"o}nnen.
+keine M{\"0}glichkeit hat, mit diesem Server eine Verbindung aufbauen zu können.
%Die genaue Spezifikation der Abwicklung der Verbindung zwischen und Client und Server kann in ServAppTech und in Service-Discovery entnommen werden.
Also nun hat ein Client das richtige Passwort eingeben und die Verbindung mit dem Server konnte erfolgreich aufgebaut werden. An dieser Stelle wollen
wir noch betonen, dass der Dozent selbst entscheiden kann, ob ein Passwort zum Verbindungsaufbau mit dem PVS-Server vom Client aus eingegeben werden
soll oder nicht. Dafür wird eine Checkbox auf dem pvsmgr-GUI eingebaut, die beim Ankreuzen per SIGNAL-SLOT die Funktion
-\textit{PVSConnectionManager::getManager()->setNeedPassword(bool needed)} aufruft, wobei mit \textit{needed=TRUE} wird ein Passwort ben{\"o}tigt. \\
-Nun wollen wir erl{\"a}utern wie der Server mit einer bestehenden Verbindung umgeht.~\\
+\textit{PVSConnectionManager::getManager()->setNeedPassword(bool needed)} aufruft, wobei mit \textit{needed=TRUE} wird ein Passwort benötigt. \\
+Nun wollen wir erläutern wie der Server mit einer bestehenden Verbindung umgeht.~\\
\subsection{Server-Seite}
-Wir hatten schon erw{\"a}hnt, dass der Server 2 Ansichtsmöglichkeiten zur Annzeige eines verbundenen Client verf{\"u}gt.
+Wir hatten schon erwähnt, dass der Server 2 Ansichtsmöglichkeiten zur Annzeige eines verbundenen Client verfügt.
Nachdem ein Client mit dem Server eine Verbindung erfolgreich aufgebaut hat, wird fast zeitgleich erstmal der Client
links in der Connection-Liste angezeigt und dann wird eine VNC-Verbindung zwischen Client und Server so aufgebaut, dass auf der rechten
Seite (\textit{Connectionwindow}) das Client-Frame angezeigt werden kann. Jeder Frame wird so beschriftet,
-dass es jeder Zeit m{\"o}glich wird, aus einem Client in der Liste (links) den entsprechenden Frame (recht) anzuordnen.\\
+dass es jeder Zeit möglich wird, aus einem Client in der Liste (links) den entsprechenden Frame (recht) anzuordnen.\\
-Somit hat der Server einen besseren {\"U}berblick {\"u}ber die gesamten vorhandenen Verbindungen. Der Server kann also jegliche verf{\"u}gbare
- Aktion ausf{\"u}hren. Der Betreiber (der Dozent) des pvsmgr verf{\"u}gt {\"u}ber eine zweite Maschine, die an einen Beamer angeschlossen
-wird und auf dieser Maschine l{\"a}uft ein PVS-Client. Dieser Client wird als \textit{Superclient} bezeichnet
-und verf{\"u}gt dementsprechend gegen{\"u}ber anderen Clients über einen Sonderstatus. Z.B: bei einer LockAll-Aktion wird er nicht
-gesperrt und dabei muss geachtet werden, dass ein auf dem Superclient projektierter Client auch nicht gesperrt wird.\\
+Somit hat der Server einen besseren {\"U}berblick über die gesamten vorhandenen Verbindungen. Der Server kann also jegliche verfügbare
+ Aktion ausführen. Der Betreiber (der Dozent) des pvsmgr verfügt über eine zweite Maschine, die an einen Beamer angeschlossen
+wird und auf dieser Maschine läuft ein PVS-Client. Dieser Client wird als \textit{Superclient} bezeichnet und verfügt dementsprechend gegenüber anderen Clients über einen Sonderstatus. Z.B: bei einer LockAll-Aktion wird er nicht gesperrt und dabei muss geachtet werden, dass ein auf dem Superclient projektierter Client auch nicht gesperrt wird.
\section{Verbindungsverwaltung und Projektion}
@@ -176,6 +173,4 @@ Soll ein Client als Ziel zu einer existierenden Projektion hinzugefügt werden,
Zusätzlich zu den Verbindungsdaten werden Qualitätsoptionen zu der gesendeten Nachricht hinzugefügt. Die Qualitätsoption ist ein Integerwert 0,1 oder 2 wobei 0 der besten Qualität, 2 der schlechtesten Qualität entspricht. Dieser Wert wird an den Zielclient einer Projektion gesendet, welcher die Qualitätseinstellungen des VNC-Viewers entsprechend anpasst. Aktuell wird die Qualität immer auf 0 gesetzt, da noch die Einstellungsmöglichkeiten in der GUI fehlen.
\subsection{Remote Help}
-Remote Help funktioniert analog zur Projektion, jedoch ist hier zu gewährleisten, dass jeweils nur ein Quellclient und ein Zielclient ausgewählt werden, da es nicht sinnvoll ist, Tastatur und Maus eines Clients von mehreren anderen Clients aus zu steuern. Anstelle des Passworts wird das RW-Passwort des Clients verwendet. Die Möglichkeit, die Maus und die Tastatur eines Clients zu steuern, ist mit dem verwendeten VNC-Server schon gegeben, für die Steuerkonsole ändert sich hier nichts, lediglich der VNC Viewer muss die Tastatureingaben und die Mausbewegung an den VNC Server weitergeben (siehe hierzu auch \ref{pvsclient-remotehelp} Tastatur und Maussteuerung).
-
-
+Remote Help funktioniert analog zur Projektion, jedoch ist hier zu gewährleisten, dass jeweils nur ein Quellclient und ein Zielclient ausgewählt werden, da es nicht sinnvoll ist, Tastatur und Maus eines Clients von mehreren anderen Clients aus zu steuern. Anstelle des Passworts wird das RW-Passwort des Clients verwendet. Die Möglichkeit, die Maus und die Tastatur eines Clients zu steuern, ist mit dem verwendeten VNC-Server schon gegeben, für die Steuerkonsole ändert sich hier nichts, lediglich der VNC Viewer muss die Tastatureingaben und die Mausbewegung an den VNC Server weitergeben (siehe hierzu auch \ref{pvsclient-remotehelp} Tastatur und Maussteuerung). \ No newline at end of file
diff --git a/doc/LaTeX/intro/0000-chapter.tex b/doc/LaTeX/intro/0000-chapter.tex
index 6b3319b..c3c5efe 100644
--- a/doc/LaTeX/intro/0000-chapter.tex
+++ b/doc/LaTeX/intro/0000-chapter.tex
@@ -2,13 +2,13 @@
\label{einleitung}
\index{Einleitung} \index{Video Switch} \index{Laptop} \index{VGA} \index{DVI} \index{Klassenraum} \index{Student Control Panel} \index{Idee}
-Video-Switches für Klassenräume sind schon seit langem auf dem Markt: Sie setzen typischerweise auf eine Hardware-Lösung, die das Verlegen von vielen Metern Kabel bei dadurch erzwungener statischer Anordnung der Rechner verlangt. Sie sind nicht nur aufgrund des Einsatzes spezieller Hardware relativ teuer, sondern unflexibel bei technischen Weiterentwicklungen: Höhere Bildschirmauflösungen oder der Wechsel vom VGA auf den DVI oder PS2 auf den USB-Stecker sind nur durch einen Komplettaustausch oder unangenehme Kompromisse zu haben. Ziemlich ungeeignet erweisen sich hardware-basierte Lösungen beim Einsatz mobiler Geräte wie Laptops. Zudem erschweren sie die Veränderung der ursprünglichen Aufstellung der Maschinen und schaffen damit ungünstige Bedingungen für neue didaktische Konzepte.
+Video-Switches für Klassenräume sind schon seit langem auf dem Markt: Sie setzen typischerweise auf eine Hardware-Lösung, die das Verlegen von vielen Metern Kabel bei dadurch erzwungener statischer Anordnung der Rechner verlangt. Sie sind nicht nur aufgrund des Einsatzes spezieller Hardware relativ teuer, sondern unflexibel bei technischen Weiterentwicklungen: Höhere Bildschirmauflösungen oder der Wechsel vom VGA- auf den DVI-Connector bzw. Display-Port oder die Ablösung von PS2 durch USB sind nur durch einen Komplettaustausch oder unangenehme Kompromisse zu haben. Ziemlich ungeeignet erweisen sich hardware-basierte Lösungen beim Einsatz mobiler Geräte wie Laptops. Generell erschweren sie die Veränderung der ursprünglichen Aufstellung der Maschinen und schaffen damit ungünstige Bedingungen für neue didaktische Konzepte.
\begin{figure}[h]
\center
\includegraphics[width=11.5cm]{bilder/studentctlpanel.png}
\caption{Student Control Panel des Edubuntu-Pakets, welches im Umfeld von Linux-Terminalservern eingesetzt werden kann.\label{uscp}}
\end{figure}
-Neben den Hardware-basierten Varianten existieren inzwischen eine Reihe von Software-Produkten. Leider bieten sie keine optimalen Lösungen: Neben oft exorbitanten Lizenzkosten, die oft mit einem didaktisch und konzeptionell fragwürdigen Feature-Set begründet werden, orientieren sie sich an einem einzigen auf den Schulungs-PCs festinstalliertem Betriebssystem. Oft stehen sie nur für ausgewählte Microsoft-Betriebssysteme zur Verfügung und können damit nicht dem Anspruch einer breiten und allgemeinen universitären Umgebung entsprechen. Zudem kommen regelmäßige, typischerweise kostenpflichtige Produkt-Updates hinzu, denen sich nur begrenzt ausweichen läßt.
+Neben den Hardware-basierten Varianten existieren inzwischen eine Reihe von Software-Produkten. Leider bieten sie keine optimalen Lösungen: Neben typischerweise exorbitanten Lizenzkosten, die oft mit einem didaktisch und konzeptionell fragwürdigen Feature-Set begründet werden, orientieren sie sich an einem einzigen auf den Schulungs-PCs festinstalliertem Betriebssystem. Oft stehen die Produkte nur für ausgewählte Microsoft-Betriebssysteme zur Verfügung und können damit nicht dem Anspruch einer breit angelegten Umgebung entsprechen, wie sie in Universitäten, Bildungseinrichtungen aber auch durchaus in Schulen vorzufinden ist. Zudem kommen regelmäßige, typischerweise kostenpflichtige Produkt-Updates hinzu, denen sich nur begrenzt ausweichen läßt.
Dem soll ein eigener Ansatz entgegengesetzt werden, der die eingangs genannten Beschränkungen aufhebt und dem Anspruch einer modernen universitären computer-gestützten Lehre entgegenkommt. Das Projekt soll stufenweise von einer einfachen Basislösung in Rückmeldung mit den Lehrenden weiterentwickelt werden. Ein Open-Source-Ansatz gewährleistet zudem eine größere Nachhaltigkeit. Selbst bei einer Projekteinstellung können andere auf den Code weiterhin zurückgreifen und damit einerseits bestehende Installationen aktualisieren und andererseits eigene Entwicklungen schneller vorantreiben.
diff --git a/doc/LaTeX/intro/0100-funktionen.tex b/doc/LaTeX/intro/0100-funktionen.tex
index 0dbac13..47799e4 100644
--- a/doc/LaTeX/intro/0100-funktionen.tex
+++ b/doc/LaTeX/intro/0100-funktionen.tex
@@ -10,7 +10,7 @@ In der verfügbaren Version wurden eine Reihe von Features realisiert. Hierzu zÃ
\begin{figure}[h]
\center
\includegraphics[width=11.5cm]{bilder/studentctlpanel.png}
-\caption{Student Control Panel des Edubuntu-Pakets, welches im Umfeld von Linux-Terminalservern eingesetzt werden kann.\label{uscp}}
+\caption{Die Steuerkonsole des Pool Video Switches in ihrer Hauptansicht. Diese grafische Applikation sollte sinnvollerweise auf einem eigenen Desktop oder komplett eigenen Rechner laufen.\label{uscp}}
\end{figure}
Bei der Realisierung wurde einerseits auf die Absicherung der Steuerverbindungen und andererseits auf die Aspekte des Datenschutzes geachtet. Anders als bei vergleichbaren Produkten liegt in der Standardinstallation die Kontrolle bei den Teilnehmern.
diff --git a/doc/LaTeX/user/0001-chapter.tex b/doc/LaTeX/user/0001-chapter.tex
index 200ffa5..3e1c42d 100644
--- a/doc/LaTeX/user/0001-chapter.tex
+++ b/doc/LaTeX/user/0001-chapter.tex
@@ -56,7 +56,7 @@ Auf dem Bild \ref{fig:pvsdummy} kann man verbundene Clients (\textit{Nicht dummy
befindet sich die korrespondierte IP-Adresse. Der grüne Punkt ganz rechts im Gegenteil zum dummy-Frame zeigt, dass der Client gerade Online ist.\\
Für die Verbundene Clients besteht die Möglichkeit die VNC-Quality (HIGH, MEDIUM oder LOW) jeder Zeit einzustellen. Mit \textit{Set Password} kann der Manager ganz bequem
festlegen, ob die Clients zur Verbindung mit dem pvsmgr ein von System generiertes Passwort eingeben müssen oder nicht. Auf dem Toolbar werden weitere Funktionen wie:
-Screeshots aufnehmen, Chat mit dem einzelnen Client starten oder alle Clients auf einem Klick zu blockieren. Das Blockieren der Clients schließt natürlich der Dozent-Rechner
+Screeshots aufnehmen, Chat mit dem einzelnen Client starten, ferngesteuert auf den markierten Clients Prozesse starten, eine Prozessliste zu öffnen in der die Prozesse sämtlicher verbundenen Clients angezeigt werden oder alle Clients auf einem Klick zu blockieren. Das Blockieren der Clients schließt natürlich der Dozent-Rechner
aus. Der Dozent-Rechner hebt sich von einem anderer verbundenen Machine durch den Rot-Blau Zeichnen neben dem grünen Punkt hervor.
\\
Befindet sich die Maus über einem VNC-Frame, so ist über dem Bildschirminhalt eine Reihe von
@@ -93,8 +93,44 @@ es erscheint dann ein Menü, aus dem die gewünschte Aktion ausgewählt werden k
{\em Vorsicht:} Die Steuerkonsole fragt vor der Ausführung einer Aktion nicht noch einmal
nach.
\\ \\
-Im letzten Punkt dieser Abschnitt wollen wir die vorhandenen Tastenkürzel vorstellen.
+\subsection{Remote Prozesse starten}
+\label{Prozesse starten}
+Über den Button aus der Abbildung \ref{png:Prozessestarten} kann der Dialog um Prozesse ferngesteuert zu starten geöffnet werden. Es muss mindestens ein Client ausgewählt werden, auf dem der eingegebene Prozess gestartet werden soll. Der Dialog (Abbildung \ref{png:Prozessestarten}) bietet folgende Funktionen:\\
+\begin{enumerate}
+ \item Diese Liste bietet den Dozenten die Möglichkeit sich bestimmte Prozesse abzuspeichern und bequem aufzurufen. Prozesse werden grundsätzlich nur mit Beschreibung abgespeichert, fehlt entweder die Beschreibung oder der Prozess selbst wird der Eintrag nichtmehr gespeichert.\\
+ Ein Klick auf die Liste fügt den ausgewählten Prozess in das Textfeld ein. Mit Doppelklick auf ein Feld der Liste kann dieses Element editiert werden, so sind sowohl die Beschreibung, als auch der Prozess editierbar. Um einen Eintrag zu löschen reicht es dessen Prozess oder Beschreibung zu entfernen und mit einem Klick auf Speichern zu übernehmen. Der Speichern-Button fügt automatisch eine leere Zeile an das Ende der Liste an, um weitere Priozesse abspeichern zu können.
+ \item Prozesse die in diesem Textfeld eingetragen sind werden mit einem Klick auf Start nach einer erneuten Abfrage auf dem Client gestartet, Änderungen an der Liste werden dabei gespeichert, der Dialog geschlossen. Ein Klick auf Abbrechen schließt den Dialog ohne die Prozessliste erneut zu speichern und ohne den Prozess zu starten.
+\end{enumerate}
+Schlägt das ferngesteuerte Starten fehl wird dies in den Logdateien angezeigt.
+\begin{figure}[h]
+ \centering
+ \includegraphics[scale=0.6]{bilder/runprocess.png}
+ \caption{Dialog um Prozesse ferngesteuert zu starten und zugehöriger Button links}
+ \label{png:Prozessestarten}
+\end{figure}
+
+\subsection{Remote Prozessliste anzeigen}
+\label{Prozessliste}
+Hier ein Überblick über die Prozessliste (Siehe Abbildung \ref{png:Prozessliste}). Die Prozessliste kann über die Toolbar in der PVS Steuerkonsole über den Button aus der Abbildung \ref{png:Prozessliste} angezeigt werden.
+\begin{enumerate}
+ \item Anzeige der Tabs - hier wird für jeden verbundenen Client ein neuer Reiter erstellt, ein Klick auf den Reiter aktiviert die Anzeige für diesen Client. Die Prozessliste wird daraufhin aktualisiert.
+ \item Prozessliste - Hier werden die Prozesse des gewählten Clients angezeigt, in den Spalten stehen die ProzessID, der Name und die Commandline. Die Prozessliste wird alle 5 Sekunden aktualisiert, ausser es ist mindestens eine Zeile markiert. Es können mehrere Zeilen markiert werden, sie müssen nicht zusammenhängen.
+ \item Buttons Refresh und Stop process - mit Refresh wird die Liste aktualisiert, unabhängig davon, ob Zeilen markiert wurden. Ein Klick auf Stop process beendet die markierten Prozesse nach einer erneuten Abfrage.
+ \item Start Process - Ein eingegebener Prozess wird auf dem aktuellen Client gestartet.
+\end{enumerate}
+Mit einem Klick auf Close werden die Prozesslisten geschlossen.
+\begin{figure}[h]
+ \centering
+ \includegraphics[scale=0.5]{bilder/processlist.png}
+ \caption{Prozessliste und zugehöriger Button links}
+ \label{png:Prozessliste}
+\end{figure}
+\\
+
+
+
+Im letzten Punkt dieses Abschnitts wollen wir die vorhandenen Tastenkürzel vorstellen.
\subsection{Tastenkürzel für PVS-Server}
\label{Taste}
Einige schlaue Tastenkombinationen sollen die Ausnutzung der PVS-Konsole erleichten.
diff --git a/misc/pvs.conf b/misc/pvs.conf
index 93c4ac5..0e71bc8 100644
--- a/misc/pvs.conf
+++ b/misc/pvs.conf
@@ -2,8 +2,7 @@
script=/usr/local/bin/pvs-vncsrv
[Permissions]
-vnc_lecturer=ro
+vnc_lecturer=no
vnc_other=no
allow_chat=T
allow_filetransfer=T
-
diff --git a/src/core/pvsConnectionManager.cpp b/src/core/pvsConnectionManager.cpp
index db302c4..d1442dd 100644
--- a/src/core/pvsConnectionManager.cpp
+++ b/src/core/pvsConnectionManager.cpp
@@ -226,33 +226,69 @@ void PVSConnectionManager::onCommand(PVSMsg command)
QString id = int2String(command.getSndID());
if (message.startsWith("START"))
{
- QString msgcontent = message.remove(0,6);
- if (msgcontent.startsWith("ERROR"))
- {
- ConsoleLog writeError("[Client: " + id + ", PROCESS] could not start: " +msgcontent.remove(0,6));
- }
- else
+ message.remove(0,6);
+ if (message.startsWith("ERROR"))
{
- //ConsoleLog writeLine(QString("[Client: " + id + ", PROCESS] started: " +msgcontent));
+ int e = string2Int(message.remove(0,6));
+ message.remove(0,2);
+ switch (e)
+ {
+ case 0:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] could not start: "+message+" is missing or insufficient permissions");
+ break;
+ case 1:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" crashed");
+ break;
+ case 2:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" timed out");
+ break;
+ case 3:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" read error");
+ break;
+ case 4:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" write error");
+ break;
+ default:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+": unknown error");
+ break;
+ }
}
}
- if (message.startsWith("STOP"))
- {
- QString msgcontent = message.remove(0,5);
- if (msgcontent.startsWith("ERROR"))
- {
- ConsoleLog writeError("[Client: " + id + ", PROCESS] could not stop: " +msgcontent.remove(0,6));
- }
- else
- {
- //ConsoleLog writeLine(QString("[Client: " + id + ", PROCESS] stopped: " +msgcontent));
- }
+ else if (message.startsWith("STOP"))
+ {
+ message.remove(0,5);
+ if (message.startsWith("ERROR"))
+ {
+ int e = string2Int(message.remove(0,6));
+ message.remove(0,2);
+ switch (e)
+ {
+ case 0:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] could not stop: "+message+" is missing or insufficient permissions");
+ break;
+ case 1:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" crashed");
+ break;
+ case 2:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" timed out");
+ break;
+ case 3:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" read error");
+ break;
+ case 4:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+" write error");
+ break;
+ default:
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] "+message+": unknown error");
+ break;
+ }
+ }
}
- if (message.startsWith("SHOW"))
+ else if (message.startsWith("SHOW"))
{
QString msgcontent = message.remove(0,5);
if (msgcontent.startsWith("ERROR"))
- ConsoleLog writeError("[Client: " + id + ", PROCESS] could not show processes: " +msgcontent.remove(0,6));
+ ConsoleLog writeError("[Client: " + id + ", PROCESS] could not show processes.");
else if (msgcontent.startsWith("clear"))
tmp->clearProcessesVector();
else if (msgcontent.startsWith("finished"))
diff --git a/src/gui/mainWindow.cpp b/src/gui/mainWindow.cpp
index 1376851..beb80f4 100644
--- a/src/gui/mainWindow.cpp
+++ b/src/gui/mainWindow.cpp
@@ -68,6 +68,8 @@ MainWindow::MainWindow(QWidget *parent) :
_aboutDialog = new AboutDialog(this);
+ displayedClientNameEnum = 0;
+
PVSConnectionManager::getManager();
//set the maximum width for list content
@@ -112,8 +114,6 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->actionProjection, SIGNAL(triggered()), this, SLOT(projecttoolbar()));
connect(ui->actionUnprojection, SIGNAL(triggered()), this, SLOT(unprojecttoolbar()));
connect(ui->actionDozent, SIGNAL(triggered()), this, SLOT(setdozenttoolbar()));
- connect(ui->actionShowProcesses, SIGNAL(triggered()), this, SLOT(showProcesses()));
- connect(ui->actionStartProcess, SIGNAL(triggered()), this, SLOT(startProcess()));
// Ui specific settings
@@ -791,57 +791,47 @@ void MainWindow::unCloseUp(ConnectionFrame* connFrame)
conWin->setCloseupFrame(NULL);
}
-/* Perform some action if actionShowProcesses button was pressed
- *
- */
+// Perform some action if actionShowProcesses button was pressed
void MainWindow::showProcesses()
{
- std::list<QString>* selectedClients =
- MainWindow::getConnectionList()->getSelectedClients();
- if (selectedClients->size() >= 1)
+ if (PVSConnectionManager::getManager()->getConnections().size() > 0)
{
- ProcessDialog procDialog;
- procDialog.exec();
-
+ ProcessDialog procShowDialog(0,displayedClientNameEnum);
+ procShowDialog.exec();
}
- else
- {
- QString
- message =
- QString(
- tr(
- "This operation can only be performed if you have selected at least one Client!"));
- QMessageBox::information(this, "PVS", message);
- }
-
}
-/* Perform some action if actionStartProcess button was pressed
- *
- */
+// Perform some action if actionStartProcess button was pressed
void MainWindow::startProcess()
{
std::list<QString>* selectedClients =
MainWindow::getConnectionList()->getSelectedClients();
if (selectedClients->size() >= 1)
{
- // do stuff
- /*PVSClient * pvsClient =
- PVSConnectionManager::getManager()->getClientFromIp(
- selectedClients->front().toStdString().c_str());*/
-
- ProcessesStartDialog procD;
- QString myString = NULL;
- int result = procD.exec();
-
- if (result == 1)
+ ProcessesStartDialog procStartDialog;
+ procToStart = "";
+ int result = procStartDialog.exec();
+ if (result == 1) //if result == 1 we clicked send on our button then
+ //procToStart is set to the text that was given in our messageEdit
{
- myString = MainWindow::getWindow()->getProcessesDialog();
- if(!myString.isEmpty())
- MainWindow::getConnectionWindow()->commandStations("STARTPROCESS",myString);
+ std::list<QString>::iterator itSelected;
+ for (itSelected = selectedClients->begin(); itSelected != selectedClients->end();
+ itSelected++)
+ {
+ std::list<PVSClient*> listAll =
+ PVSConnectionManager::getManager()->getConnections();
+ for (std::list<PVSClient*>::iterator itAll = listAll.begin();
+ itAll != listAll.end(); itAll++)
+ {
+ if ((*itSelected) == (*itAll)->getIp())
+ {
+ (*itAll)->sendMessage(PVSCOMMAND, "STARTPROCESS", procToStart);
+ break;
+ }
+ }
+ }
}
-
}
else
{
@@ -901,6 +891,7 @@ void MainWindow::createProfile()
void MainWindow::showusername()
{
+ displayedClientNameEnum = 2;
MainWindow::getConnectionList()->setColumnHidden(2, false);
MainWindow::getConnectionList()->setColumnHidden(0, true);
MainWindow::getConnectionList()->setColumnHidden(1, true);
@@ -908,6 +899,7 @@ void MainWindow::showusername()
void MainWindow::showname()
{
+ displayedClientNameEnum = 0;
MainWindow::getConnectionList()->setColumnHidden(0, false);
MainWindow::getConnectionList()->setColumnHidden(1, true);
MainWindow::getConnectionList()->setColumnHidden(2, true);
@@ -915,6 +907,7 @@ void MainWindow::showname()
void MainWindow::showip()
{
+ displayedClientNameEnum = 1;
MainWindow::getConnectionList()->setColumnHidden(1, false);
MainWindow::getConnectionList()->setColumnHidden(2, true);
MainWindow::getConnectionList()->setColumnHidden(0, true);
@@ -1314,6 +1307,11 @@ void MainWindow::configureNetwork()
}
}
+int MainWindow::getDisplayedClientNameEnum()
+{
+ return displayedClientNameEnum;
+}
+
MainWindow* MainWindow::myself = NULL;
ConnectionList* MainWindow::conList = NULL;
ConnectionWindow* MainWindow::conWin = NULL;
diff --git a/src/gui/mainWindow.h b/src/gui/mainWindow.h
index 58787ed..272d057 100644
--- a/src/gui/mainWindow.h
+++ b/src/gui/mainWindow.h
@@ -96,8 +96,8 @@ public:
void setMsgDialog(QString msgd){msgDialog = msgd;};
QString getMsgDialog(){return msgDialog;};
- void setProcessesDialog(QString procd){procDialog = procd;};
- QString getProcessesDialog(){return procDialog;};
+ void setProcessesDialog(QString procd){procToStart = procd;};
+ QString getProcessesDialog(){return procToStart;};
bool isLockAllStatus()
{
@@ -106,8 +106,6 @@ public:
void appendLogMsg();
-
-
protected:
void closeEvent(QCloseEvent *e);
void changeEvent(QEvent *e);
@@ -128,6 +126,8 @@ private:
QString _sessionName;
QString _profilName;
+ int displayedClientNameEnum; //to tell if username, loginname or ip is shown in clientList
+
QStringList _chatListClients;
@@ -139,7 +139,7 @@ private:
AboutDialog *_aboutDialog;
QString msgDialog;
- QString procDialog;
+ QString procToStart;
bool bgimage;
bool locked, locked1;
bool force_square;
@@ -188,6 +188,7 @@ public slots:
void startChatDialog();
void showProcesses();
void startProcess();
+ int getDisplayedClientNameEnum();
private slots:
void onToggleLog(bool showtime);
diff --git a/src/gui/processWidget.cpp b/src/gui/processWidget.cpp
index 9b59b2a..38dd2ae 100644
--- a/src/gui/processWidget.cpp
+++ b/src/gui/processWidget.cpp
@@ -28,10 +28,11 @@ ProcessWidget::ProcessWidget(QWidget *parent, PVSClient *cl):
client = cl;
connect( prowui->startButton, SIGNAL( clicked()), this, SLOT( startProcess()));
- connect( prowui->refreshButton, SIGNAL( clicked()), this, SLOT( refrProcessList()));
+ connect( prowui->refreshButton, SIGNAL( clicked()), this, SLOT( resendProcessList()));
connect( prowui->stopButton, SIGNAL( clicked()), this, SLOT( stopProcess()));
connect( client, SIGNAL( processVectorReady(bool)), this, SLOT( refrProcessList()));
+ //tell client we want to see his processes
sendCommand("SHOWPROCESSES", "");
}
@@ -39,7 +40,7 @@ void ProcessWidget::startProcess()
{
QMessageBox::StandardButton start = QMessageBox::question(0,
tr("PVS Start Process"), tr("Do you want to start the process: ") + prowui->processLineEdit->text() +
- tr(" on User '") + client->getDesktopName() + tr("' ?"),
+ tr(" on this Client?"),
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
if (start == QMessageBox::Ok)
@@ -50,15 +51,33 @@ void ProcessWidget::startProcess()
prowui->processLineEdit->clear();
}
-void ProcessWidget::refrProcessList()
+void ProcessWidget::resendProcessList()
{
+ sendCommand("SHOWPROCESSES", "");
+}
+
+void ProcessWidget::refrProcessList(bool timerEvent)
+{
+ if (timerEvent)
+ {
+ if (prowui->processTable->selectedItems().length() > 0)
+ return;
+ else
+ {
+ resendProcessList();
+ return;
+ }
+ }
+
+ //remove every item of our list
for(int i=prowui->processTable->rowCount(); i == 0; i--)
{
prowui->processTable->removeRow(i);
}
prowui->processTable->setRowCount(0);
- QVector<QString> processes = client->getProcessesVector();
+ //read every entry of the vector - split it - and put it to the list
+ QVector<QString> processes = client->getProcessesVector();
for (int i=0; i<processes.size(); i++)
{
prowui->processTable->setRowCount(i+1);
@@ -68,22 +87,47 @@ void ProcessWidget::refrProcessList()
prowui->processTable->setItem(i,j,new QTableWidgetItem(processesList.at(j),0));
}
}
- prowui->processTable->selectRow(0);
}
void ProcessWidget::stopProcess()
{
if (prowui->processTable->rowCount() > 0)
{
- QMessageBox::StandardButton start = QMessageBox::question(0,
- tr("PVS Start Process"), tr("Do you want to stop the process: ") + prowui->processTable->item(prowui->processTable->currentRow(),1)->text() +
- tr(" on User '") + client->getDesktopName() + tr("' ?"),
- QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
- if (start == QMessageBox::Ok)
- {
- sendCommand("KILLPROCESS", prowui->processTable->item(prowui->processTable->currentRow(),0)->text());
- sendCommand("SHOWPROCESSES", "");
- }
+ //get a list of all selected items
+ QList<QTableWidgetItem *> selectedItems = prowui->processTable->selectedItems();
+ QList<int> rows;
+ for (int i=0;i<selectedItems.length();i++)
+ {
+ //only add rows one time
+ if (rows.indexOf(selectedItems.at(i)->row()) < 0)
+ rows.append(selectedItems.at(i)->row());
+ }
+ //append names of processes
+ QString processesMessage = "";
+ for (int i=0;i<rows.size();i++)
+ {
+ if (i==0)
+ processesMessage.append(QString(tr(" ")));
+ else
+ processesMessage.append(QString(tr(",")));
+ processesMessage.append(prowui->processTable->item(rows.at(i),1)->text());
+ processesMessage.append(QString(tr(" ")));
+ }
+
+ QMessageBox::StandardButton start = QMessageBox::question(0,
+ tr("PVS Start Process"), tr("Do you want to stop the process(es):") + processesMessage +
+ tr("on this Client?"),
+ QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
+ if (start == QMessageBox::Ok)
+ {
+ //send KILLPROCESS for every row
+ for (int i=0;i<rows.size();i++)
+ {
+ sendCommand("KILLPROCESS", prowui->processTable->item(rows.at(i),0)->text());
+ }
+ }
+ //tell client to update his list
+ sendCommand("SHOWPROCESSES", "");
}
}
diff --git a/src/gui/processWidget.h b/src/gui/processWidget.h
index 7e7eb72..4d696eb 100644
--- a/src/gui/processWidget.h
+++ b/src/gui/processWidget.h
@@ -17,9 +17,9 @@ class ProcessWidget: public QWidget
public:
ProcessWidget(QWidget *parent, PVSClient *client);
~ ProcessWidget();
- QAbstractItemModel *model;
+
public slots:
- void refrProcessList();
+ void refrProcessList(bool timerEvent = false);
private:
Ui::ProcessWidget *prowui;
@@ -29,6 +29,7 @@ private:
private slots:
void startProcess();
void stopProcess();
+ void resendProcessList();
void sendCommand(QString ident, QString message);
};
diff --git a/src/gui/processesDialog.cpp b/src/gui/processesDialog.cpp
index cda76ea..7c0405c 100644
--- a/src/gui/processesDialog.cpp
+++ b/src/gui/processesDialog.cpp
@@ -1,5 +1,5 @@
/*
-# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+# Copyright (c) 2010 - OpenSLX Project, Computer Center University of Freiburg
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
@@ -17,9 +17,8 @@
#include "processesDialog.h"
#include "ui_processesDialog.h"
#include <src/gui/processWidget.h>
-//#include <src/gui/mainWindow.h>
-ProcessDialog::ProcessDialog(QDialog *parent) :
+ProcessDialog::ProcessDialog(QDialog *parent, int displayedClientNameEnum) :
QDialog(parent),
procui(new Ui::ProcessesDialog)
{
@@ -28,6 +27,7 @@ ProcessDialog::ProcessDialog(QDialog *parent) :
tWidget = new QTabWidget;
procui->grLayout->addWidget(tWidget);
+ //if we click on another tab we refresh the list of this client
connect( tWidget, SIGNAL( currentChanged(int)), this, SLOT( currChanged()));
std::list<PVSClient*> listAll =
@@ -35,23 +35,38 @@ ProcessDialog::ProcessDialog(QDialog *parent) :
for (std::list<PVSClient*>::iterator it = listAll.begin(); it
!= listAll.end(); it++)
{
- if (*it == NULL || (*it)->getConnectionFrame() == NULL) continue;
- if ((*it)->getConnectionFrame()->getFrame() &&
- /*!(*it)->getConnectionFrame()->getFrame()->isDozent() &&*/
- (*it)->getVNCConnection())
+ //display ip/login name/user name the same way we do in our clientlist
+ switch (displayedClientNameEnum)
+ {
+ case 1:
+ tWidget->addTab(new ProcessWidget(0, *it), (*it)->getIp());
+ break;
+ case 2:
+ tWidget->addTab(new ProcessWidget(0, *it), (*it)->getLoginName());
+ break;
+ default:
tWidget->addTab(new ProcessWidget(0, *it), (*it)->getUserName());
- else if (!(*it)->getConnectionFrame()->getFrame())
- ConsoleLog writeError(QString("The Frame connection from client: ").
- append((*it)->getConnectionFrame()->getTaskbarTitle()).
- append(QString(" is corrupted. Reconnect the client it again.")));
+ break;
+ }
}
+
+ QTimer *refreshTimer = new QTimer(this);
+ connect(refreshTimer, SIGNAL(timeout()), this, SLOT(currRefr()));
+ refreshTimer->start(5000);
+
}
// if other Tab is activated we say our tab to refresh the processList
void ProcessDialog::currChanged()
{
ProcessWidget *temp = static_cast<ProcessWidget*>(tWidget->currentWidget());
- temp->refrProcessList();
+ temp->refrProcessList(false);
+}
+
+void ProcessDialog::currRefr()
+{
+ ProcessWidget *temp = static_cast<ProcessWidget*>(tWidget->currentWidget());
+ temp->refrProcessList(true);
}
ProcessDialog::~ProcessDialog()
diff --git a/src/gui/processesDialog.h b/src/gui/processesDialog.h
index 9d98136..2c821fb 100644
--- a/src/gui/processesDialog.h
+++ b/src/gui/processesDialog.h
@@ -6,6 +6,7 @@
#include <src/gui/processWidget.h>
#include <src/gui/mainWindow.h>
#include <list>
+#include <QTimer>
namespace Ui {
@@ -21,7 +22,7 @@ class MainWindow;
class ProcessDialog : public QDialog {
Q_OBJECT
public:
- ProcessDialog(QDialog *parent = 0);
+ ProcessDialog(QDialog *parent = 0, int displayedClientNameEnum = 0);
~ProcessDialog();
@@ -32,6 +33,7 @@ private:
private slots:
void currChanged();
+ void currRefr();
};
#endif // PROCESSESDIALOG_H
diff --git a/src/gui/processesStartDialog.cpp b/src/gui/processesStartDialog.cpp
index b4c8c79..e0a6286 100644
--- a/src/gui/processesStartDialog.cpp
+++ b/src/gui/processesStartDialog.cpp
@@ -19,57 +19,127 @@
#include <src/gui/mainWindow.h>
ProcessesStartDialog::ProcessesStartDialog(QWidget *parent) :
- QDialog(parent)
+ QDialog(parent),
+ procStartUi(new Ui::ProcessesStartDialog)
{
- textLabel = new QLabel;
- textLabel->setText("Process to start:");
+ procStartUi->setupUi(this);
+ connect( procStartUi->sendButton, SIGNAL( clicked()), this, SLOT( send()));
+ connect( procStartUi->cancelButton, SIGNAL( clicked()), this, SLOT( notSend()));
+ connect( procStartUi->saveButton, SIGNAL( clicked()), this, SLOT ( save()));
- messageEdit = new QLineEdit;
+ //if we click or double click one of our items we put it in our message
+ connect( procStartUi->processesList, SIGNAL( cellDoubleClicked(int,int)), this, SLOT ( itemClicked(int,int)));
+ connect( procStartUi->processesList, SIGNAL( cellClicked(int,int)), this, SLOT ( itemClicked(int,int)));
- layout = new QGridLayout;
-
- sendButton = new QPushButton(tr("Start"));
- cancelButton = new QPushButton(tr("Cancel"));
-
- connect( sendButton, SIGNAL( clicked()), this, SLOT( send()));
- connect( cancelButton, SIGNAL( clicked()), this, SLOT( NotSend()));
-
- layout->addWidget(textLabel,0,0);
- layout->addWidget(messageEdit,1,0);
- layout->addWidget(cancelButton,2,0);
- layout->addWidget(sendButton,2,0);
-
- setLayout(layout);
- setWindowTitle(tr("PVS start Process"));
+ listProcesses();
}
ProcessesStartDialog::~ProcessesStartDialog()
{
- //delete procstartui;
+ //
}
void ProcessesStartDialog::send()
{
- QString procd = messageEdit->text();
- MainWindow::getWindow()->setProcessesDialog(procd);
- messageEdit->clear();
- emit accept();
+ QString procd = procStartUi->message->text();
+ save(); //save (if we made changes to our list)
+ if (procd.length()>0)
+ {
+ QMessageBox::StandardButton start = QMessageBox::question(0,
+ tr("PVS Start Process"), tr("Do you want to start the process: ") + procd +
+ tr(" on the selected Clients?"),
+ QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok);
+
+ if (start == QMessageBox::Ok)
+ {
+ //write name of process to setProcessesDialog
+ MainWindow::getWindow()->setProcessesDialog(procd);
+ procStartUi->message->clear();
+ emit accept();
+ }
+ }
}
-void ProcessesStartDialog::NotSend()
+void ProcessesStartDialog::notSend()
{
- messageEdit->clear();
+ procStartUi->message->clear();
emit reject();
}
-/*void ProcessesStartDialog::changeEvent(QEvent *e)
+void ProcessesStartDialog::listProcesses()
{
- //QDialog::changeEvent(e);
- //switch (e->type()) {
- //case QEvent::LanguageChange:
- // procstartui->retranslateUi(this);
- // break;
- //default:
- // break;
- //}
-}*/
+ /*settings.beginWriteArray("RemoteProcessesList");
+ settings.setArrayIndex(0);
+ settings.setValue("command", "oowriter");
+ settings.setValue("description", "Open Office Writer");
+ settings.setArrayIndex(1);
+ settings.setValue("command", "oocalc");
+ settings.setValue("description", "Open Office Calc");
+ settings.endArray();*/
+
+ //read from settings
+ int size = settings.beginReadArray("RemoteProcessesList");
+ for (int i = 0; i < size; ++i)
+ {
+ settings.setArrayIndex(i);
+ procStartUi->processesList->setRowCount(i+1);
+ procStartUi->processesList->setItem(i, 0, new QTableWidgetItem(settings.value("command").toString(),0));
+ procStartUi->processesList->setItem(i, 1, new QTableWidgetItem(settings.value("description").toString(),0));
+ }
+ settings.endArray();
+
+ //add empty items to our List
+ QString empty = " ";
+ procStartUi->processesList->setRowCount(procStartUi->processesList->rowCount()+1);
+ procStartUi->processesList->setItem(procStartUi->processesList->rowCount()-1, 0, new QTableWidgetItem(empty,0));
+ procStartUi->processesList->setItem(procStartUi->processesList->rowCount()-1, 1, new QTableWidgetItem(empty,0));
+}
+
+void ProcessesStartDialog::save()
+{
+ //if we delete items from our list we increment our decrement - to decrement our arrayindex
+ int decrement = 0;
+
+ // if both our last elements are empty dont read them
+ // we need this if we have added new elements
+ if ((procStartUi->processesList->item(procStartUi->processesList->rowCount()-1, 0) != 0) &&
+ (procStartUi->processesList->item(procStartUi->processesList->rowCount()-1, 1) != 0))
+ {
+ settings.beginWriteArray("RemoteProcessesList");
+ for (int i = 0; i < procStartUi->processesList->rowCount(); ++i)
+ {
+ //if elements are only whitespaces we ignore them
+ if ((procStartUi->processesList->item(i, 0)->text().remove(QRegExp("\\s")) != "") &&
+ (procStartUi->processesList->item(i, 1)->text().remove(QRegExp("\\s")) != ""))
+ {
+ settings.setArrayIndex(i-decrement);
+ settings.setValue("command", procStartUi->processesList->item(i, 0)->text());
+ settings.setValue("description", procStartUi->processesList->item(i, 1)->text());
+ } else decrement++; //and increment our decrement
+ }
+ settings.endArray();
+ }
+ else
+ {
+ settings.beginWriteArray("RemoteProcessesList");
+ for (int i = 0; i < procStartUi->processesList->rowCount()-1; ++i)
+ {
+ if ((procStartUi->processesList->item(i, 0)->text().remove(QRegExp("\\s")) != "") &&
+ (procStartUi->processesList->item(i, 1)->text().remove(QRegExp("\\s")) != ""))
+ {
+ settings.setArrayIndex(i-decrement);
+ settings.setValue("command", procStartUi->processesList->item(i, 0)->text());
+ settings.setValue("description", procStartUi->processesList->item(i, 1)->text());
+ } else decrement++;
+ }
+ settings.endArray();
+ }
+ listProcesses();
+}
+
+void ProcessesStartDialog::itemClicked(int row, int column)
+{
+ //if last item exists we put it in our message
+ if (procStartUi->processesList->item(row, 0) != 0)
+ procStartUi->message->setText(procStartUi->processesList->item(row, 0)->text());
+}
diff --git a/src/gui/processesStartDialog.h b/src/gui/processesStartDialog.h
index 61aee4f..358a356 100644
--- a/src/gui/processesStartDialog.h
+++ b/src/gui/processesStartDialog.h
@@ -3,29 +3,30 @@
#include <QDialog>
#include <QtGui>
+#include "ui_processesStartDialog.h"
+namespace Ui {
+ class ProcessesStartDialog;
+}
class MainWindow;
-
+class QDialog;
class ProcessesStartDialog : public QDialog {
Q_OBJECT
public:
ProcessesStartDialog(QWidget *parent = 0);
~ProcessesStartDialog();
-/*protected:
- void changeEvent(QEvent *e);*/
-
private:
- QGridLayout *layout;
- QLabel *textLabel;
- QLineEdit *messageEdit;
- QPushButton *sendButton;
- QPushButton *cancelButton;
+ Ui::ProcessesStartDialog *procStartUi;
+ QSettings settings;
private slots:
void send();
- void NotSend();
+ void notSend();
+ void listProcesses();
+ void save();
+ void itemClicked(int row, int column);
};
#endif // PROCESSESSTARTDIALOG_H
diff --git a/src/gui/ui/mainwindow.ui b/src/gui/ui/mainwindow.ui
index d444092..a9d5cad 100644
--- a/src/gui/ui/mainwindow.ui
+++ b/src/gui/ui/mainwindow.ui
@@ -557,7 +557,7 @@
<string>showProcesses</string>
</property>
<property name="toolTip">
- <string>Show Processes of the selected Client</string>
+ <string>Show processes of all clients</string>
</property>
</action>
<action name="actionStartProcess">
@@ -568,6 +568,9 @@
<property name="text">
<string>Start Process</string>
</property>
+ <property name="toolTip">
+ <string>Start process on the selected client(s)</string>
+ </property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
diff --git a/src/gui/ui/mainwindowtouch.ui b/src/gui/ui/mainwindowtouch.ui
index 3480f09..12a2f2b 100644
--- a/src/gui/ui/mainwindowtouch.ui
+++ b/src/gui/ui/mainwindowtouch.ui
@@ -28,8 +28,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>1335</width>
- <height>673</height>
+ <width>1329</width>
+ <height>660</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_3">
@@ -648,7 +648,7 @@
<string>showProcesses</string>
</property>
<property name="toolTip">
- <string>Show Processes of the selected Client</string>
+ <string>Show processes of all clients</string>
</property>
</action>
<action name="actionStartProcess">
@@ -659,6 +659,9 @@
<property name="text">
<string>Start Process</string>
</property>
+ <property name="toolTip">
+ <string>Start process on the selected client(s)</string>
+ </property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
diff --git a/src/gui/ui/processWidget.ui b/src/gui/ui/processWidget.ui
index 3e7f55e..a759dc1 100644
--- a/src/gui/ui/processWidget.ui
+++ b/src/gui/ui/processWidget.ui
@@ -26,7 +26,7 @@
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
- <string>Prozessliste</string>
+ <string>List of processes</string>
</property>
<widget class="QWidget" name="verticalLayoutWidget">
<property name="geometry">
@@ -56,7 +56,7 @@
<bool>true</bool>
</property>
<property name="selectionMode">
- <enum>QAbstractItemView::SingleSelection</enum>
+ <enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
@@ -147,14 +147,14 @@
<item>
<widget class="QPushButton" name="refreshButton">
<property name="text">
- <string>Aktualisieren</string>
+ <string>Refresh</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stopButton">
<property name="text">
- <string>Prozess beenden</string>
+ <string>Stop process</string>
</property>
</widget>
</item>
@@ -180,7 +180,7 @@
</size>
</property>
<property name="title">
- <string>Prozess starten</string>
+ <string>Start Process</string>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
@@ -198,7 +198,7 @@
<item>
<widget class="QPushButton" name="startButton">
<property name="text">
- <string>Prozess starten</string>
+ <string>Start Process</string>
</property>
</widget>
</item>
diff --git a/src/gui/ui/processesDialog.ui b/src/gui/ui/processesDialog.ui
index 4ac4859..14d2403 100644
--- a/src/gui/ui/processesDialog.ui
+++ b/src/gui/ui/processesDialog.ui
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>Prozesse</string>
+ <string>Processes</string>
</property>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="geometry">
diff --git a/src/gui/ui/processesStartDialog.ui b/src/gui/ui/processesStartDialog.ui
index 5d8c7ee..2003c57 100644
--- a/src/gui/ui/processesStartDialog.ui
+++ b/src/gui/ui/processesStartDialog.ui
@@ -6,58 +6,191 @@
<rect>
<x>0</x>
<y>0</y>
- <width>393</width>
- <height>109</height>
+ <width>524</width>
+ <height>309</height>
</rect>
</property>
<property name="windowTitle">
<string>Start Process</string>
</property>
- <widget class="QWidget" name="layoutWidget">
+ <widget class="QWidget" name="verticalLayoutWidget_3">
<property name="geometry">
<rect>
- <x>20</x>
- <y>20</y>
- <width>351</width>
- <height>71</height>
+ <x>10</x>
+ <y>10</y>
+ <width>503</width>
+ <height>291</height>
</rect>
</property>
- <layout class="QVBoxLayout" name="verticalLayout">
+ <layout class="QVBoxLayout" name="outerVerticalLayout">
<item>
- <widget class="QLineEdit" name="message"/>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <property name="spacing">
- <number>5</number>
- </property>
+ <layout class="QVBoxLayout" name="upperVerticalLayout">
<item>
- <spacer name="horizontalSpacer">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>108</width>
- <height>20</height>
- </size>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Either use a command from this list or type in the process in the lower field.</string>
</property>
- </spacer>
+ </widget>
</item>
<item>
- <widget class="QPushButton" name="cancel">
- <property name="text">
- <string>Cancel</string>
+ <widget class="QTableWidget" name="processesList">
+ <property name="verticalScrollBarPolicy">
+ <enum>Qt::ScrollBarAsNeeded</enum>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAlwaysOff</enum>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::DoubleClicked|QAbstractItemView::SelectedClicked</set>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="gridStyle">
+ <enum>Qt::DotLine</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
</property>
+ <property name="cornerButtonEnabled">
+ <bool>false</bool>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="horizontalHeaderCascadingSectionResizes">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderDefaultSectionSize">
+ <number>200</number>
+ </attribute>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="horizontalHeaderCascadingSectionResizes">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderVisible">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderDefaultSectionSize">
+ <number>200</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>Command</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Description</string>
+ </property>
+ </column>
</widget>
</item>
<item>
- <widget class="QPushButton" name="send">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="saveButton">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="lowerVerticalLayout">
+ <item>
+ <widget class="QLabel" name="label">
<property name="text">
- <string>Send</string>
+ <string>Process to start:</string>
</property>
</widget>
</item>
+ <item>
+ <widget class="QLineEdit" name="message"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>108</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="sendButton">
+ <property name="text">
+ <string>Start</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
</layout>
</item>
</layout>
diff --git a/src/pvs.cpp b/src/pvs.cpp
index 755eea5..843a725 100755
--- a/src/pvs.cpp
+++ b/src/pvs.cpp
@@ -268,15 +268,18 @@ void PVS::onCommand(PVSMsg cmdMessage)
}
if (ident.compare("STARTPROCESS") == 0)
{
+ processName = message;
QProcess *proc = new QProcess( this );
proc->start(message); //we try to run the process with the name message
- _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "START Process "+message+": started"));
+ connect( proc, SIGNAL( error(QProcess::ProcessError)), this, SLOT( processStartErrorOccured(QProcess::ProcessError)));
return;
}
if (ident.compare("KILLPROCESS") == 0)
{
+ processName = message;
QProcess *proc = new QProcess( this );
proc->start("kill "+message); //we try to kill the process with the given ID
+ connect( proc, SIGNAL( error(QProcess::ProcessError)), this, SLOT( processStopErrorOccured(QProcess::ProcessError)));
return;
}
@@ -937,21 +940,28 @@ QString PVS::getConfigValue(QString key)
void PVS::showProc()
{
+ QString settings = getConfigValue("RemoteProcess/filter");
+ QStringList filter = settings.split(" ");
+
//look at procfs
QDir procfs("/proc");
- QStringList proc = procfs.entryList();
+ QStringList procList = procfs.entryList();
int uid = getuid();
bool write;
-
- for (int i=0;i<proc.length();i++) //every directory in /proc is checked
+ if (procList.length() < 1) //if we can't read procfs for any reason
+ {
+ _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW ERROR"));
+ return;
+ }
+ for (int i=0;i<procList.length();i++) //every directory in /proc is checked
{
write = false;
- QString tmp = proc.at(i);
- QString snd = "";
- if (!tmp.contains(QRegExp("\\D"))) //we have to check if name is number
+ QString tempFolder = procList.at(i);
+ QString tempSend = "";
+ if (!tempFolder.contains(QRegExp("\\D"))) //we have to check if name is number
{
QString name = "";
- QFile file("/proc/"+tmp+QString("/status")); //read status file
+ QFile file("/proc/"+tempFolder+QString("/status")); //read status file
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
@@ -962,28 +972,31 @@ void PVS::showProc()
if (line.startsWith("Name:")) //to get the name of our process
{
name = line.remove(0,6);
- snd.append(tmp).append(QString("<#>")).append(line).append("<#>");
- //lets check if the process belongs to our PVS better not to show it if we dont want to crash PVS
- } else if (line.startsWith("Gid:")) //and to check that the process is a user process
- //we had to read name first because every file in /proc
- //has size 0 byte
+ tempSend.append(tempFolder).append(QString("<#>")).append(line).append("<#>");
+ //lets check if the process belongs to our PVS. better not to show it if we dont want to crash PVS
+ } else if (line.startsWith("Uid:")) //and to check that the process is a user process
+ //we had to read name first
{
- line.remove(0,5);
- if (line.startsWith(QString::number(uid)))
+ line.remove(QRegExp("\\D")); //remove all non-digit characters (letters+whitespaces)
+ int llength = line.size();
+ line.remove(llength/4,llength);
+ if (line == QString::number(uid))
write = true;
else break;
-
}
line = in.readLine();
}
- if (write)
+ if (write) //check if user belongs to pvs
{
- if ((name.startsWith("pvs")) || (name.startsWith("dbus")))
+ for (int i=0;i<filter.size();i++)
+ {
+ if (name == (filter.at(i)))
write = false;
+ }
}
if (write) //if process belongs to user (and not to PVS) we go on
{
- QFile file("/proc/"+tmp+QString("/cmdline")); //and read cmdline
+ QFile file("/proc/"+tempFolder+QString("/cmdline")); //and read cmdline
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
@@ -991,14 +1004,27 @@ void PVS::showProc()
QString line = in.readLine();
while (!line.isNull())
{
- int templength = snd.length()+3;
- snd.append(line.left(150+templength)); //but only up to a length of 150-name-id-seperators
+ int templength = tempSend.length()+3;
+ tempSend.append(line.left(150+templength)); //but only up to a length of 150-name-id-seperators
break;
}
}
if (write) //if process belongs to user we send the line to client
- _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW "+snd));
+ _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW "+tempSend));
}
}
_pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "SHOW finished")); //at the end we send that every process has been sent
}
+
+//tell connectionManager that error occured
+void PVS::processStartErrorOccured(QProcess::ProcessError error)
+{
+ _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "START ERROR "+QString::number(error)+" "+processName));
+ processName = "";
+}
+
+void PVS::processStopErrorOccured(QProcess::ProcessError error)
+{
+ _pvsServerConnection->sendMessage(PVSMsg(PVSCOMMAND, "PROCESSES", "STOP ERROR "+QString::number(error)+" "+processName));
+ processName = "";
+}
diff --git a/src/pvs.h b/src/pvs.h
index db87b8e..e3ff329 100755
--- a/src/pvs.h
+++ b/src/pvs.h
@@ -171,6 +171,7 @@ private:
int _timerLockTest;
int _timerLockDelay;
+ QString processName;
// input event handling:
InputEventHandlerChain _inputEventHandlers;
@@ -192,6 +193,8 @@ private Q_SLOTS:
void outgoingMulticastTransferDelete(qulonglong transferID);
void incomingMulticastTransferDelete(qulonglong transferID);
void onIncomingMulticastTransferRetry(QString const& sender, qulonglong transferID);
+ void processStartErrorOccured(QProcess::ProcessError error);
+ void processStopErrorOccured(QProcess::ProcessError error);
private:
QSettings _settings;