Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
OpenBoard
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lifo
Nicolas Ollinger
OpenBoard
Commits
edb3fd50
Commit
edb3fd50
authored
Apr 12, 2012
by
Claudio Valerio
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
new littles gui improvements on teacher guide
parent
20d6e93e
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
48 additions
and
370 deletions
+48
-370
UBMediaWidget.cpp
src/customWidgets/UBMediaWidget.cpp
+36
-1
UBMediaWidget.h
src/customWidgets/UBMediaWidget.h
+6
-0
UBMediaPlayer.cpp
src/gui/UBMediaPlayer.cpp
+0
-257
UBMediaPlayer.h
src/gui/UBMediaPlayer.h
+0
-106
UBTeacherGuideWidget.cpp
src/gui/UBTeacherGuideWidget.cpp
+1
-1
UBTeacherGuideWidgetsTools.cpp
src/gui/UBTeacherGuideWidgetsTools.cpp
+4
-3
UBTeacherGuideWidgetsTools.h
src/gui/UBTeacherGuideWidgetsTools.h
+1
-0
gui.pri
src/gui/gui.pri
+0
-2
No files found.
src/customWidgets/UBMediaWidget.cpp
View file @
edb3fd50
...
...
@@ -34,6 +34,8 @@ UBMediaWidget::UBMediaWidget(eMediaType type, QWidget *parent, const char *name)
,
mBorder
(
5
)
,
mpMediaContainer
(
NULL
)
,
mpCover
(
NULL
)
// , mpVideoStackedWidget(NULL)
// , mpSnapshotVideoWidget(NULL)
{
SET_STYLE_SHEET
();
...
...
@@ -72,6 +74,8 @@ UBMediaWidget::~UBMediaWidget()
DELETEPTR
(
mpPlayStopButton
);
DELETEPTR
(
mpAudioOutput
);
DELETEPTR
(
mpVideoWidget
);
// DELETEPTR(mpVideoStackedWidget);
// DELETEPTR(mpSnapshotVideoWidget);
DELETEPTR
(
mpMediaObject
);
DELETEPTR
(
mpCover
);
}
...
...
@@ -117,6 +121,13 @@ void UBMediaWidget::showEvent(QShowEvent* event)
QWidget
::
showEvent
(
event
);
}
void
UBMediaWidget
::
hideEvent
(
QHideEvent
*
event
)
{
if
(
mpMediaObject
->
state
()
==
Phonon
::
PlayingState
)
mpMediaObject
->
stop
();
UBActionableWidget
::
hideEvent
(
event
);
}
/**
* \brief Create the media player
*/
...
...
@@ -127,10 +138,17 @@ void UBMediaWidget::createMediaPlayer()
mpMediaContainer
->
setLayout
(
&
mMediaLayout
);
if
(
eMediaType_Video
==
mType
){
mMediaLayout
.
setContentsMargins
(
10
,
10
,
25
,
10
);
mMediaLayout
.
setContentsMargins
(
10
,
10
,
10
,
10
);
if
(
isVisible
()){
mpVideoWidget
=
new
Phonon
::
VideoWidget
(
this
);
mMediaLayout
.
addStretch
(
1
);
// mpVideoStackedWidget = new QStackedWidget(this);
// mpVideoStackedWidget->addWidget(mpVideoWidget);
// mpSnapshotVideoWidget = new QLabel(this);
// mpVideoStackedWidget->addWidget(mpSnapshotVideoWidget);
// mMediaLayout.addWidget(mpVideoStackedWidget,0);
mMediaLayout
.
addWidget
(
mpVideoWidget
,
0
);
mMediaLayout
.
addStretch
(
1
);
Phonon
::
createPath
(
mpMediaObject
,
mpVideoWidget
);
...
...
@@ -170,6 +188,22 @@ void UBMediaWidget::adaptSizeToVideo()
}
}
//void UBMediaWidget::updateView(Phonon::State nextState)
//{
// if(eMediaType_Video == mType){
// if(nextState != Phonon::PlayingState){
// const QPixmap& snapshot = QPixmap::grabWindow(mpVideoWidget->winId());
// if(snapshot.size().width()!= 0){
// mpSnapshotVideoWidget->setPixmap(snapshot);
// mpVideoStackedWidget->setCurrentWidget(mpSnapshotVideoWidget);
// }
// }
// else
// mpVideoStackedWidget->setCurrentWidget(mpVideoWidget);
// }
//}
/**
* \brief Handle the media state change notification
* @param newState as the new state
...
...
@@ -198,6 +232,7 @@ void UBMediaWidget::onStateChanged(Phonon::State newState, Phonon::State oldStat
mpPauseButton
->
setEnabled
(
false
);
mpSlider
->
setValue
(
0
);
}
//updateView(newState);
}
}
...
...
src/customWidgets/UBMediaWidget.h
View file @
edb3fd50
...
...
@@ -21,6 +21,7 @@
#include <QLabel>
#include <QSlider>
#include <QMouseEvent>
#include <QStackedWidget>
#include <phonon/MediaObject>
#include <phonon/VideoWidget>
...
...
@@ -75,6 +76,7 @@ public:
protected
:
void
resizeEvent
(
QResizeEvent
*
ev
);
void
showEvent
(
QShowEvent
*
event
);
void
hideEvent
(
QHideEvent
*
event
);
/** The current media file path */
QString
mFilePath
;
...
...
@@ -89,6 +91,7 @@ private slots:
private
:
void
createMediaPlayer
();
void
adaptSizeToVideo
();
// void updateView(Phonon::State nextState);
/** The current media type */
eMediaType
mType
;
...
...
@@ -122,6 +125,9 @@ private:
QLabel
*
mpCover
;
/** The media url */
QString
mUrl
;
// QStackedWidget* mpVideoStackedWidget;
// QLabel* mpSnapshotVideoWidget;
};
#endif // UBMEDIAWIDGET_H
src/gui/UBMediaPlayer.cpp
deleted
100644 → 0
View file @
20d6e93e
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QtGui>
#include "UBMediaPlayer.h"
#define SLIDER_RANGE 8
MediaVideoWidget
::
MediaVideoWidget
(
UBMediaPlayer
*
player
,
QWidget
*
parent
)
:
Phonon
::
VideoWidget
(
parent
),
m_player
(
player
)
/*, m_action(this)*/
{
//NOOP
}
void
MediaVideoWidget
::
timerEvent
(
QTimerEvent
*
e
)
{
if
(
e
->
timerId
()
==
m_timer
.
timerId
())
{
//let's store the cursor shape
#ifndef QT_NO_CURSOR
setCursor
(
Qt
::
BlankCursor
);
#endif
}
Phonon
::
VideoWidget
::
timerEvent
(
e
);
}
UBMediaPlayer
::
UBMediaPlayer
()
:
playButton
(
0
),
m_AudioOutput
(
Phonon
::
VideoCategory
),
m_videoWidget
(
new
MediaVideoWidget
(
this
))
{
setContextMenuPolicy
(
Qt
::
CustomContextMenu
);
m_videoWidget
->
setContextMenuPolicy
(
Qt
::
CustomContextMenu
);
QSize
buttonSize
(
26
,
20
);
playButton
=
new
QPushButton
(
this
);
playIcon
=
style
()
->
standardIcon
(
QStyle
::
SP_MediaPlay
);
pauseIcon
=
style
()
->
standardIcon
(
QStyle
::
SP_MediaPause
);
playButton
->
setIcon
(
playIcon
);
slider
=
new
Phonon
::
SeekSlider
(
this
);
slider
->
setMediaObject
(
&
m_MediaObject
);
QVBoxLayout
*
vLayout
=
new
QVBoxLayout
(
this
);
vLayout
->
setContentsMargins
(
1
,
1
,
1
,
1
);
initVideoWindow
();
vLayout
->
addWidget
(
&
m_videoWindow
);
QVBoxLayout
*
buttonPanelLayout
=
new
QVBoxLayout
();
#ifndef Q_WS_WIN
m_videoWindow
.
hide
();
#endif
progressLabel
=
new
QLabel
(
this
);
QWidget
*
sliderPanel
=
new
QWidget
(
this
);
QHBoxLayout
*
sliderLayout
=
new
QHBoxLayout
();
sliderLayout
->
addWidget
(
playButton
);
sliderLayout
->
addWidget
(
slider
);
sliderLayout
->
addWidget
(
progressLabel
);
sliderLayout
->
setContentsMargins
(
0
,
0
,
0
,
0
);
sliderPanel
->
setLayout
(
sliderLayout
);
buttonPanelLayout
->
addWidget
(
sliderPanel
);
buttonPanelLayout
->
setContentsMargins
(
0
,
0
,
0
,
0
);
#ifdef Q_OS_MAC
buttonPanelLayout
->
setSpacing
(
0
);
#endif
QWidget
*
buttonPanelWidget
=
new
QWidget
(
this
);
buttonPanelWidget
->
setSizePolicy
(
QSizePolicy
::
Preferred
,
QSizePolicy
::
Fixed
);
buttonPanelWidget
->
setLayout
(
buttonPanelLayout
);
vLayout
->
addWidget
(
buttonPanelWidget
);
QHBoxLayout
*
labelLayout
=
new
QHBoxLayout
();
vLayout
->
addLayout
(
labelLayout
);
setLayout
(
vLayout
);
connect
(
playButton
,
SIGNAL
(
clicked
()),
this
,
SLOT
(
playPause
()));
connect
(
&
m_MediaObject
,
SIGNAL
(
finished
()),
this
,
SLOT
(
finished
()));
connect
(
&
m_MediaObject
,
SIGNAL
(
stateChanged
(
Phonon
::
State
,
Phonon
::
State
)),
this
,
SLOT
(
stateChanged
(
Phonon
::
State
,
Phonon
::
State
)));
connect
(
&
m_MediaObject
,
SIGNAL
(
bufferStatus
(
int
)),
this
,
SLOT
(
bufferStatus
(
int
)));
connect
(
&
m_MediaObject
,
SIGNAL
(
hasVideoChanged
(
bool
)),
this
,
SLOT
(
hasVideoChanged
(
bool
)));
playButton
->
setEnabled
(
false
);
m_audioOutputPath
=
Phonon
::
createPath
(
&
m_MediaObject
,
&
m_AudioOutput
);
Phonon
::
createPath
(
&
m_MediaObject
,
m_videoWidget
);
resize
(
minimumSizeHint
());
}
void
UBMediaPlayer
::
stateChanged
(
Phonon
::
State
newstate
,
Phonon
::
State
oldstate
)
{
if
(
oldstate
==
Phonon
::
LoadingState
)
{
QRect
videoHintRect
=
QRect
(
QPoint
(
0
,
0
),
m_videoWindow
.
sizeHint
());
QApplication
::
desktop
()
->
screenGeometry
().
intersected
(
videoHintRect
);
if
(
m_MediaObject
.
hasVideo
())
{
qApp
->
processEvents
();
resize
(
sizeHint
());
}
else
resize
(
minimumSize
());
}
switch
(
newstate
)
{
case
Phonon
:
:
ErrorState
:
if
(
m_MediaObject
.
errorType
()
==
Phonon
::
FatalError
)
{
playButton
->
setEnabled
(
false
);
}
else
{
m_MediaObject
.
pause
();
}
QMessageBox
::
warning
(
this
,
"Phonon UBMediaPlayer"
,
m_MediaObject
.
errorString
(),
QMessageBox
::
Close
);
break
;
case
Phonon
:
:
StoppedState
:
// Fall through
case
Phonon
:
:
PausedState
:
playButton
->
setIcon
(
playIcon
);
if
(
m_MediaObject
.
currentSource
().
type
()
!=
Phonon
::
MediaSource
::
Invalid
){
playButton
->
setEnabled
(
true
);
}
else
{
playButton
->
setEnabled
(
false
);
}
break
;
case
Phonon
:
:
PlayingState
:
playButton
->
setEnabled
(
true
);
playButton
->
setIcon
(
pauseIcon
);
if
(
m_MediaObject
.
hasVideo
())
m_videoWindow
.
show
();
// Fall through
case
Phonon
:
:
BufferingState
:
break
;
case
Phonon
:
:
LoadingState
:
break
;
}
}
void
UBMediaPlayer
::
setVolume
(
qreal
volume
)
{
m_AudioOutput
.
setVolume
(
volume
);
}
void
UBMediaPlayer
::
initVideoWindow
()
{
QVBoxLayout
*
videoLayout
=
new
QVBoxLayout
();
videoLayout
->
addWidget
(
m_videoWidget
);
videoLayout
->
setContentsMargins
(
0
,
0
,
0
,
0
);
m_videoWindow
.
setLayout
(
videoLayout
);
m_videoWindow
.
setMinimumSize
(
60
,
40
);
}
void
UBMediaPlayer
::
playPause
()
{
if
(
m_MediaObject
.
state
()
==
Phonon
::
PlayingState
)
m_MediaObject
.
pause
();
else
{
if
(
m_MediaObject
.
currentTime
()
==
m_MediaObject
.
totalTime
())
m_MediaObject
.
seek
(
0
);
m_MediaObject
.
play
();
}
}
void
UBMediaPlayer
::
setFile
(
const
QString
&
fileName
)
{
setWindowTitle
(
fileName
.
right
(
fileName
.
length
()
-
fileName
.
lastIndexOf
(
'/'
)
-
1
));
m_MediaObject
.
setCurrentSource
(
Phonon
::
MediaSource
(
fileName
));
}
void
UBMediaPlayer
::
setLocation
(
const
QString
&
location
)
{
setWindowTitle
(
location
.
right
(
location
.
length
()
-
location
.
lastIndexOf
(
'/'
)
-
1
));
m_MediaObject
.
setCurrentSource
(
Phonon
::
MediaSource
(
QUrl
::
fromEncoded
(
location
.
toUtf8
())));
m_MediaObject
.
play
();
}
void
UBMediaPlayer
::
openFile
()
{
QStringList
fileNames
=
QFileDialog
::
getOpenFileNames
(
this
,
QString
(),
QDesktopServices
::
storageLocation
(
QDesktopServices
::
MusicLocation
));
m_MediaObject
.
clearQueue
();
if
(
fileNames
.
size
()
>
0
)
{
QString
fileName
=
fileNames
[
0
];
setFile
(
fileName
);
for
(
int
i
=
1
;
i
<
fileNames
.
size
();
i
++
)
m_MediaObject
.
enqueue
(
Phonon
::
MediaSource
(
fileNames
[
i
]));
}
}
void
UBMediaPlayer
::
bufferStatus
(
int
percent
)
{
if
(
percent
==
100
)
progressLabel
->
setText
(
QString
());
else
{
QString
str
=
QString
::
fromLatin1
(
"(%1%)"
).
arg
(
percent
);
progressLabel
->
setText
(
str
);
}
}
void
UBMediaPlayer
::
rewind
()
{
m_MediaObject
.
seek
(
0
);
}
void
UBMediaPlayer
::
forward
()
{
QList
<
Phonon
::
MediaSource
>
queue
=
m_MediaObject
.
queue
();
if
(
queue
.
size
()
>
0
)
{
m_MediaObject
.
setCurrentSource
(
queue
[
0
]);
m_MediaObject
.
play
();
}
}
void
UBMediaPlayer
::
openUrl
()
{
QSettings
settings
;
settings
.
beginGroup
(
QLatin1String
(
"BrowserMainWindow"
));
QString
sourceURL
=
settings
.
value
(
"location"
).
toString
();
bool
ok
=
false
;
sourceURL
=
QInputDialog
::
getText
(
this
,
tr
(
"Open Location"
),
tr
(
"Please enter a valid address here:"
),
QLineEdit
::
Normal
,
sourceURL
,
&
ok
);
if
(
ok
&&
!
sourceURL
.
isEmpty
())
{
setLocation
(
sourceURL
);
settings
.
setValue
(
"location"
,
sourceURL
);
}
}
void
UBMediaPlayer
::
finished
()
{
}
void
UBMediaPlayer
::
hasVideoChanged
(
bool
bHasVideo
)
{
m_videoWindow
.
setVisible
(
bHasVideo
);
}
void
UBMediaPlayer
::
resizeEvent
(
QResizeEvent
*
pEvent
)
{
Q_UNUSED
(
pEvent
);
}
src/gui/UBMediaPlayer.h
deleted
100644 → 0
View file @
20d6e93e
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UBUBMediaPlayer_H
#define UBUBMediaPlayer_H
#include <QtGui/QWidget>
#include <QtGui/QApplication>
#include <QtCore/QTimerEvent>
#include <QtGui/QShowEvent>
#include <QtGui/QIcon>
#include <QtCore/QBasicTimer>
#include <QtGui/QAction>
#include <phonon/audiooutput.h>
#include <phonon/backendcapabilities.h>
#include <phonon/effect.h>
#include <phonon/effectparameter.h>
#include <phonon/effectwidget.h>
#include <phonon/mediaobject.h>
#include <phonon/seekslider.h>
#include <phonon/videowidget.h>
#include <phonon/volumeslider.h>
QT_BEGIN_NAMESPACE
class
QPushButton
;
class
QLabel
;
class
QSlider
;
class
QTextEdit
;
QT_END_NAMESPACE
class
UBMediaPlayer
;
class
MediaVideoWidget
:
public
Phonon
::
VideoWidget
{
Q_OBJECT
;
public
:
MediaVideoWidget
(
UBMediaPlayer
*
player
,
QWidget
*
parent
=
0
);
protected
:
void
timerEvent
(
QTimerEvent
*
e
);
private
:
UBMediaPlayer
*
m_player
;
QBasicTimer
m_timer
;
};
class
UBMediaPlayer
:
public
QWidget
{
Q_OBJECT
public
:
UBMediaPlayer
();
void
setFile
(
const
QString
&
text
);
void
setLocation
(
const
QString
&
location
);
void
setVolume
(
qreal
volume
);
public
slots
:
void
openFile
();
void
rewind
();
void
forward
();
void
finished
();
void
playPause
();
protected
:
void
resizeEvent
(
QResizeEvent
*
pEvent
);
private
slots
:
void
stateChanged
(
Phonon
::
State
newstate
,
Phonon
::
State
oldstate
);
void
bufferStatus
(
int
percent
);
void
openUrl
();
void
hasVideoChanged
(
bool
);
private
:
void
initVideoWindow
();
QIcon
playIcon
;
QIcon
pauseIcon
;
QPushButton
*
playButton
;
Phonon
::
SeekSlider
*
slider
;
QLabel
*
progressLabel
;
QWidget
m_videoWindow
;
Phonon
::
MediaObject
m_MediaObject
;
Phonon
::
AudioOutput
m_AudioOutput
;
MediaVideoWidget
*
m_videoWidget
;
Phonon
::
Path
m_audioOutputPath
;
};
#endif // UBUBMediaPlayer_H
src/gui/UBTeacherGuideWidget.cpp
View file @
edb3fd50
...
...
@@ -287,7 +287,7 @@ UBTeacherGuidePresentationWidget::UBTeacherGuidePresentationWidget(QWidget *pare
mpDocumentTitle
=
new
QLabel
(
this
);
mpDocumentTitle
->
setObjectName
(
"UBTGPresentationDocumentTitle"
);
mpDocumentTitle
->
setText
(
"Document title"
);
mpDocumentTitle
->
setText
(
tr
(
"Document title"
)
);
mpButtonTitleLayout
->
addWidget
(
mpModePushButton
);
mpButtonTitleLayout
->
addWidget
(
mpDocumentTitle
);
...
...
src/gui/UBTeacherGuideWidgetsTools.cpp
View file @
edb3fd50
...
...
@@ -210,7 +210,7 @@ UBTGMediaWidget::UBTGMediaWidget(QTreeWidgetItem* widget, QWidget* parent,const
setAcceptDrops
(
true
);
addWidget
(
mpDropMeWidget
);
setMinimumHeight
(
4
0
);
setMinimumHeight
(
10
0
);
}
UBTGMediaWidget
::
UBTGMediaWidget
(
QString
relativePath
,
QTreeWidgetItem
*
widget
,
QWidget
*
parent
,
const
char
*
name
)
:
QStackedWidget
(
parent
)
...
...
@@ -229,6 +229,7 @@ UBTGMediaWidget::UBTGMediaWidget(QString relativePath, QTreeWidgetItem* widget,
setObjectName
(
name
);
setAcceptDrops
(
false
);
createWorkWidget
(
mRelativePath
);
setMinimumHeight
(
200
);
}
UBTGMediaWidget
::~
UBTGMediaWidget
()
...
...
@@ -306,7 +307,7 @@ void UBTGMediaWidget::createWorkWidget(QString& path)
mpLayout
=
new
QVBoxLayout
(
mpWorkWidget
);
if
(
!
mIsPresentationMode
){
mpTitle
=
new
UBTGAdaptableText
(
mpTreeWidgetItem
,
mpWorkWidget
);
mpLayout
->
addWidget
(
mpTitle
);
mpLayout
->
addWidget
(
mpTitle
,
1
);
}
if
(
mpMediaLabelWidget
){
mpMediaLabelWidget
->
setParent
(
mpWorkWidget
);
...
...
@@ -321,6 +322,7 @@ void UBTGMediaWidget::createWorkWidget(QString& path)
mpWebView
->
setParent
(
mpWorkWidget
);
mpLayout
->
addWidget
(
mpWebView
);
}
mpWorkWidget
->
setLayout
(
mpLayout
);
addWidget
(
mpWorkWidget
);
setCurrentWidget
(
mpWorkWidget
);
updateSize
();
...
...
@@ -383,7 +385,6 @@ void UBTGMediaWidget::updateSize()
}
}
/***************************************************************************
* class UBTGUrlWdiget *
***************************************************************************/
...
...
src/gui/UBTeacherGuideWidgetsTools.h
View file @
edb3fd50
...
...
@@ -139,6 +139,7 @@ private:
QString
mMediaType
;
};
class
UBTGUrlWidget
:
public
QWidget
,
public
iUBTGSavableData
{
Q_OBJECT
...
...
src/gui/gui.pri
View file @
edb3fd50
...
...
@@ -46,7 +46,6 @@ HEADERS += src/gui/UBThumbnailView.h \
src/gui/UBLibWebView.h \
src/gui/UBDownloadWidget.h \
src/gui/UBDockDownloadWidget.h \
src/gui/UBMediaPlayer.h \
src/gui/UBDockTeacherGuideWidget.h \
src/gui/UBTeacherGuideWidget.h \
src/gui/UBTeacherGuideWidgetsTools.h \
...
...
@@ -100,7 +99,6 @@ SOURCES += src/gui/UBThumbnailView.cpp \
src/gui/UBLibWebView.cpp \
src/gui/UBDownloadWidget.cpp \
src/gui/UBDockDownloadWidget.cpp \
src/gui/UBMediaPlayer.cpp \
src/gui/UBDockTeacherGuideWidget.cpp \
src/gui/UBTeacherGuideWidget.cpp \
src/gui/UBTeacherGuideWidgetsTools.cpp \
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment