2
* main_window.cpp - main-file for iTALC-Application
4
* Copyright (c) 2004-2008 Tobias Doerffel <tobydox/at/users/dot/sf/dot/net>
6
* This file is part of iTALC - http://italc.sourceforge.net
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* General Public License for more details.
18
* You should have received a copy of the GNU General Public
19
* License along with this program (see COPYING); if not, write to the
20
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
* Boston, MA 02111-1307, USA.
30
#include <QtCore/QDir>
31
#include <QtCore/QDateTime>
32
#include <QtCore/QTimer>
33
#include <QtGui/QApplication>
34
#include <QtGui/QButtonGroup>
35
#include <QtGui/QCloseEvent>
36
#include <QtGui/QDesktopWidget>
37
#include <QtGui/QMenu>
38
#include <QtGui/QMenuBar>
39
#include <QtGui/QMessageBox>
40
#include <QtGui/QScrollArea>
41
#include <QtGui/QSplashScreen>
42
#include <QtGui/QSplitter>
43
#include <QtGui/QToolBar>
44
#include <QtGui/QToolButton>
45
#include <QtGui/QWorkspace>
46
#include <QtNetwork/QHostAddress>
48
#include "main_window.h"
49
#include "classroom_manager.h"
51
#include "italc_side_bar.h"
52
#include "overview_widget.h"
53
#include "snapshot_list.h"
54
#include "config_widget.h"
55
#include "messagebox.h"
56
#include "tool_button.h"
58
#include "isd_connection.h"
59
#include "local_system.h"
60
#include "remote_control_widget.h"
63
QSystemTrayIcon * __systray_icon = NULL;
66
extern int __isd_port;
67
extern QString __isd_host;
70
bool mainWindow::ensureConfigPathExists( void )
72
return( localSystem::ensurePathExists(
73
localSystem::personalConfigDir() ) );
77
bool mainWindow::s_atExit = FALSE;
80
mainWindow::mainWindow( int _rctrl_screen ) :
81
QMainWindow(/* 0, Qt::FramelessWindowHint*/ ),
82
m_openedTabInSideBar( 1 ),
85
m_remoteControlWidget( NULL ),
87
m_remoteControlScreen( _rctrl_screen > -1 ?
89
QApplication::desktop()->numScreens() )
91
QApplication::desktop()->screenNumber( this ) )
93
setWindowTitle( tr( "iTALC" ) + " " + VERSION );
94
setWindowIcon( QPixmap( ":/resources/logo.png" ) );
96
if( mainWindow::ensureConfigPathExists() == FALSE )
98
if( splashScreen != NULL )
100
splashScreen->hide();
102
messageBox::information( tr( "No write-access" ),
103
tr( "Could not read/write or create directory %1! "
104
"For running iTALC, make sure you're permitted to "
105
"create or write this directory." ).arg(
106
localSystem::personalConfigDir() ) );
110
QWidget * hbox = new QWidget( this );
111
QHBoxLayout * hbox_layout = new QHBoxLayout( hbox );
112
hbox_layout->setMargin( 0 );
113
hbox_layout->setSpacing( 0 );
115
// create splitter, which is used for splitting sidebar-workspaces
116
// from main-workspace
117
m_splitter = new QSplitter( Qt::Horizontal, hbox );
118
#if QT_VERSION >= 0x030200
119
m_splitter->setChildrenCollapsible( FALSE );
123
m_sideBar = new italcSideBar( italcSideBar::VSNET, hbox, m_splitter );
127
QScrollArea * sa = new QScrollArea( m_splitter );
128
sa->setBackgroundRole( QPalette::Dark );
129
sa->setFrameStyle( QFrame::NoFrame );
130
m_splitter->setStretchFactor( m_splitter->indexOf( sa ), 10 );
131
m_workspace = new clientWorkspace( sa );
134
QWidget * twp = m_sideBar->tabWidgetParent();
135
// now create all sidebar-workspaces
136
m_overviewWidget = new overviewWidget( this, twp );
137
m_classroomManager = new classroomManager( this, twp );
138
m_snapshotList = new snapshotList( this, twp );
139
m_configWidget = new configWidget( this, twp );
141
m_workspace->m_contextMenu = m_classroomManager->quickSwitchMenu();
143
// append sidebar-workspaces to sidebar
145
m_sideBar->appendTab( m_overviewWidget, ++id );
146
m_sideBar->appendTab( m_classroomManager, ++id );
147
m_sideBar->appendTab( m_snapshotList, ++id );
148
m_sideBar->appendTab( m_configWidget, ++id );
149
m_sideBar->setPosition( italcSideBar::Left );
150
m_sideBar->setTab( m_openedTabInSideBar, TRUE );
152
setCentralWidget( hbox );
153
hbox_layout->addWidget( m_sideBar );
154
hbox_layout->addWidget( m_splitter );
159
// create the action-toolbar
160
m_toolBar = new toolBar( tr( "Actions" ), this );
161
m_toolBar->layout()->setSpacing( 4 );
162
m_toolBar->setMovable( FALSE );
163
m_toolBar->setObjectName( "maintoolbar" );
164
m_toolBar->toggleViewAction()->setEnabled( FALSE );
166
addToolBar( Qt::TopToolBarArea, m_toolBar );
168
toolButton * scr = new toolButton(
169
QPixmap( ":/resources/classroom.png" ),
170
tr( "Classroom" ), QString::null,
171
tr( "Switch classroom" ),
172
tr( "Click this button to open a menu where you can "
173
"choose the active classroom." ),
174
NULL, NULL, m_toolBar );
175
scr->setMenu( m_classroomManager->quickSwitchMenu() );
176
scr->setPopupMode( toolButton::InstantPopup );
177
scr->setWhatsThis( tr( "Click on this button, to switch between "
180
m_modeGroup = new QButtonGroup( this );
184
a = new QAction( QIcon( ":/resources/overview_mode.png" ),
185
tr( "Overview mode" ), this );
186
m_sysTrayActions << a;
187
toolButton * overview_mode = new toolButton(
188
a, tr( "Overview" ), QString::null,
189
tr( "This is the default mode in iTALC and allows you "
190
"to have an overview over all visible "
191
"computers. Also click on this button for "
192
"unlocking locked workstations or for leaving "
194
this, SLOT( mapOverview() ), m_toolBar );
197
a = new QAction( QIcon( ":/resources/fullscreen_demo.png" ),
198
tr( "Fullscreen demo" ), this );
199
m_sysTrayActions << a;
200
toolButton * fsdemo_mode = new toolButton(
201
a, tr( "Fullscreen Demo" ), tr( "Stop Demo" ),
202
tr( "In this mode your screen is being displayed on "
203
"all shown computers. Furthermore the users "
204
"aren't able to do something else as all input "
205
"devices are locked in this mode." ),
206
this, SLOT( mapFullscreenDemo() ), m_toolBar );
208
a = new QAction( QIcon( ":/resources/window_demo.png" ),
209
tr( "Window demo" ), this );
210
m_sysTrayActions << a;
211
toolButton * windemo_mode = new toolButton(
212
a, tr( "Window Demo" ), tr( "Stop Demo" ),
213
tr( "In this mode your screen being displayed in a "
214
"window on all shown computers. The users are "
215
"able to switch to other windows and thus "
216
"can continue to work." ),
217
this, SLOT( mapWindowDemo() ), m_toolBar );
219
a = new QAction( QIcon( ":/resources/locked.png" ),
220
tr( "Lock/unlock desktops" ), this );
221
m_sysTrayActions << a;
222
toolButton * lock_mode = new toolButton(
223
a, tr( "Lock all" ), tr( "Unlock all" ),
224
tr( "To have all user's full attention you can lock "
225
"their desktops using this button. "
226
"In this mode all input devices are locked and "
227
"the screen is black." ),
228
this, SLOT( mapScreenLock() ), m_toolBar );
230
overview_mode->setCheckable( TRUE );
231
fsdemo_mode->setCheckable( TRUE );
232
windemo_mode->setCheckable( TRUE );
233
lock_mode->setCheckable( TRUE );
235
m_modeGroup->addButton( overview_mode, client::Mode_Overview );
236
m_modeGroup->addButton( fsdemo_mode, client::Mode_FullscreenDemo );
237
m_modeGroup->addButton( windemo_mode, client::Mode_WindowDemo );
238
m_modeGroup->addButton( lock_mode, client::Mode_Locked );
240
overview_mode->setChecked( TRUE );
244
a = new QAction( QIcon( ":/resources/text_message.png" ),
245
tr( "Send text message" ), this );
246
// m_sysTrayActions << a;
247
toolButton * text_msg = new toolButton(
248
a, tr( "Text message" ), QString::null,
249
tr( "Use this button to send a text message to all "
250
"users e.g. to tell them new tasks etc." ),
251
m_classroomManager, SLOT( sendMessage() ), m_toolBar );
254
a = new QAction( QIcon( ":/resources/power_on.png" ),
255
tr( "Power on computers" ), this );
256
m_sysTrayActions << a;
257
toolButton * power_on = new toolButton(
258
a, tr( "Power on" ), QString::null,
259
tr( "Click this button to power on all visible "
260
"computers. This way you do not have to turn "
261
"on each computer by hand." ),
262
m_classroomManager, SLOT( powerOnClients() ),
265
a = new QAction( QIcon( ":/resources/power_off.png" ),
266
tr( "Power down computers" ), this );
267
m_sysTrayActions << a;
268
toolButton * power_off = new toolButton(
269
a, tr( "Power down" ), QString::null,
270
tr( "To power down all shown computers (e.g. after "
271
"the lesson has finished) you can click this "
274
SLOT( powerDownClients() ), m_toolBar );
276
toolButton * remotelogon = new toolButton(
277
QPixmap( ":/resources/remotelogon.png" ),
278
tr( "Logon" ), QString::null,
279
tr( "Remote logon" ),
280
tr( "After clicking this button you can enter a "
281
"username and password to log on the "
282
"according user on all visible computers." ),
283
m_classroomManager, SLOT( remoteLogon() ), m_toolBar );
285
toolButton * directsupport = new toolButton(
286
QPixmap( ":/resources/remote_control.png" ),
287
tr( "Support" ), QString::null,
288
tr( "Direct support" ),
289
tr( "If you need to support someone at a certain "
290
"computer you can click this button and enter "
291
"the according hostname or IP afterwards." ),
292
m_classroomManager, SLOT( directSupport() ), m_toolBar );
294
toolButton * adjust_size = new toolButton(
295
QPixmap( ":/resources/adjust_size.png" ),
296
tr( "Adjust/align" ), QString::null,
297
tr( "Adjust windows and their size" ),
298
tr( "When clicking this button the biggest possible "
299
"size for the client-windows is adjusted. "
300
"Furthermore all windows are aligned." ),
301
m_classroomManager, SLOT( adjustWindows() ), m_toolBar );
303
toolButton * auto_arrange = new toolButton(
304
QPixmap( ":/resources/auto_arrange.png" ),
305
tr( "Auto view" ), QString::null,
306
tr( "Auto re-arrange windows and their size" ),
307
tr( "When clicking this button all visible windows "
308
"are re-arranged and adjusted." ),
309
m_classroomManager, SLOT( arrangeWindows() ), m_toolBar );
311
scr->addTo( m_toolBar );
312
overview_mode->addTo( m_toolBar );
313
fsdemo_mode->addTo( m_toolBar );
314
windemo_mode->addTo( m_toolBar );
315
lock_mode->addTo( m_toolBar );
316
text_msg->addTo( m_toolBar );
317
power_on->addTo( m_toolBar );
318
power_off->addTo( m_toolBar );
319
remotelogon->addTo( m_toolBar );
320
directsupport->addTo( m_toolBar );
321
adjust_size->addTo( m_toolBar );
322
auto_arrange->addTo( m_toolBar );
324
restoreState( QByteArray::fromBase64(
325
m_classroomManager->winCfg().toUtf8() ) );
326
QStringList hidden_buttons = m_classroomManager->toolBarCfg().
328
foreach( QAction * a, m_toolBar->actions() )
330
if( hidden_buttons.contains( a->text() ) )
332
a->setVisible( FALSE );
336
foreach( KMultiTabBarTab * tab, m_sideBar->tabs() )
338
if( hidden_buttons.contains( tab->text() ) )
340
tab->setTabVisible( FALSE );
346
if( isdConnection::initAuthentication() == FALSE )
348
if( __role != ISD::RoleTeacher )
350
__role = ISD::RoleTeacher;
353
if( splashScreen != NULL )
355
splashScreen->hide();
357
messageBox::information( tr( "No valid keys found" ),
358
tr( "No authentication-keys were found or your "
359
"old ones were broken. Please create a new "
360
"key-pair using ICA (see documentation at "
361
"http://italc.sf.net/wiki/index.php?title=Installation).\n"
362
"Otherwise you won't be able to access "
363
"computers using iTALC." ) );
367
m_localISD = new isdConnection( QHostAddress(
368
__isd_host ).toString() +
369
":" + QString::number( __isd_port ) );
370
if( m_localISD->open() != isdConnection::Connected )
372
messageBox::information( tr( "iTALC service not running" ),
373
tr( "There seems to be no iTALC service running "
374
"on this computer or the authentication-keys "
375
"aren't set up properly. The service is "
376
"required for running iTALC. Contact your "
377
"administrator for solving this problem." ),
378
QPixmap( ":/resources/stop.png" ) );
382
m_localISD->demoServerRun( __demo_quality,
383
localSystem::freePort( 5858 ) );
386
m_localISD->hideTrayIcon();
388
QIcon icon( ":/resources/icon16.png" );
389
icon.addFile( ":/resources/icon22.png" );
390
icon.addFile( ":/resources/icon32.png" );
392
__systray_icon = new QSystemTrayIcon( icon, this );
393
__systray_icon->setToolTip( tr( "iTALC Master Control" ) );
394
__systray_icon->show();
395
connect( __systray_icon, SIGNAL( activated(
396
QSystemTrayIcon::ActivationReason ) ),
397
this, SLOT( handleSystemTrayEvent(
398
QSystemTrayIcon::ActivationReason ) ) );
401
QTimer::singleShot( 2000, m_classroomManager, SLOT( updateClients() ) );
403
m_updateThread = new mainWindowUpdateThread( this );
409
mainWindow::~mainWindow()
411
m_classroomManager->doCleanupWork();
414
qApp->processEvents( QEventLoop::AllEvents, 3000 );
415
localSystem::sleep( 3000 );
418
// also delets clients
421
m_localISD->gracefulClose();
426
__systray_icon->hide();
427
delete __systray_icon;
430
qApp->processEvents( QEventLoop::AllEvents, 3000 );
431
localSystem::sleep( 3000 );
439
void mainWindow::keyPressEvent( QKeyEvent * _e )
441
if( _e->key() == Qt::Key_F11 )
443
QWidget::setWindowState( QWidget::windowState() ^
444
Qt::WindowFullScreen );
448
QMainWindow::keyPressEvent( _e );
455
void mainWindow::closeEvent( QCloseEvent * _ce )
459
m_updateThread->quit();
460
m_updateThread->wait();
461
delete m_updateThread;
462
m_updateThread = NULL;
464
QList<client *> clients = m_workspace->findChildren<client *>();
465
foreach( client * c, clients )
470
m_classroomManager->savePersonalConfig();
471
m_classroomManager->saveGlobalClientConfig();
480
void mainWindow::handleSystemTrayEvent( QSystemTrayIcon::ActivationReason _r )
484
case QSystemTrayIcon::Trigger:
485
setVisible( !isVisible() );
487
case QSystemTrayIcon::Context:
490
m.addAction( __systray_icon->toolTip() )->setEnabled( FALSE );
491
foreach( QAction * a, m_sysTrayActions )
499
QAction * rc = m.addAction( tr( "Remote control" ) );
502
m_classroomManager->visibleClients() )
504
rcm.addAction( c->name() )->
505
setData( c->hostname() );
507
connect( &rcm, SIGNAL( triggered( QAction * ) ),
509
SLOT( remoteControlClient( QAction * ) ) );
513
QAction * qa = m.addAction(
514
QIcon( ":/resources/quit.png" ),
516
connect( qa, SIGNAL( triggered( bool ) ),
517
this, SLOT( close() ) );
518
m.exec( QCursor::pos() );
529
void mainWindow::remoteControlClient( QAction * _a )
532
remoteControlDisplay( _a->data().toString(),
533
m_classroomManager->clientDblClickAction() );
539
void mainWindow::remoteControlDisplay( const QString & _hostname,
541
bool _stop_demo_afterwards )
543
QWriteLocker wl( &m_rctrlLock );
544
if( m_remoteControlWidget )
548
m_remoteControlWidget = new remoteControlWidget( _hostname, _view_only,
551
for( int i = 0; i < m_remoteControlScreen; ++i )
553
x += QApplication::desktop()->screenGeometry( i ).width();
555
m_remoteControlWidget->move( x, 0 );
556
m_stopDemo = _stop_demo_afterwards;
557
connect( m_remoteControlWidget, SIGNAL( destroyed( QObject * ) ),
558
this, SLOT( remoteControlWidgetClosed( QObject * ) ) );
564
void mainWindow::remoteControlWidgetClosed( QObject * )
566
m_rctrlLock.lockForWrite();
567
m_remoteControlWidget = NULL;
568
m_rctrlLock.unlock();
571
m_classroomManager->changeGlobalClientMode(
572
client::Mode_Overview );
580
void mainWindow::aboutITALC( void )
582
aboutDialog( this ).exec();
588
void mainWindow::changeGlobalClientMode( int _mode )
590
client::modes new_mode = static_cast<client::modes>( _mode );
591
if( new_mode == m_classroomManager->globalClientMode()/* &&
592
new_mode != client::Mode_Overview*/ )
594
m_classroomManager->changeGlobalClientMode(
595
client::Mode_Overview );
596
m_modeGroup->button( client::Mode_Overview )->setChecked(
601
m_classroomManager->changeGlobalClientMode( _mode );
611
mainWindowUpdateThread::mainWindowUpdateThread( mainWindow * _main_window ) :
613
m_mainWindow( _main_window )
615
start( QThread::LowestPriority );
621
void mainWindowUpdateThread::update( void )
623
m_mainWindow->m_localISD->handleServerMessages();
625
if( client::reloadSnapshotList() )
627
m_mainWindow->m_snapshotList->reloadList();
629
client::resetReloadOfSnapshotList();
631
// now do cleanup-work
632
m_mainWindow->getClassroomManager()->doCleanupWork();
636
void mainWindowUpdateThread::run( void )
639
connect( &t, SIGNAL( timeout() ), this, SLOT( update() ) );
640
t.start( m_mainWindow->getClassroomManager()->updateInterval() * 1000 );
648
clientWorkspace::clientWorkspace( QScrollArea * _parent ) :
650
m_contextMenu( NULL )
652
_parent->setWidget( this );
653
_parent->setWidgetResizable( TRUE );
654
setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding,
655
QSizePolicy::MinimumExpanding ) );
662
QSize clientWorkspace::sizeHint( void ) const
664
return( childrenRect().size() );
670
void clientWorkspace::contextMenuEvent( QContextMenuEvent * _event )
672
m_contextMenu->exec( _event->globalPos() );
679
#include "main_window.moc"
680
#include "italc_side_bar.moc"