allow saving a PDF, add "view_comment" state
This adds a "view_comment" in addition to "view" and "edit" state into discovery.xml. In case it is enabled, the filters let the comment commands through to core. In addition add "Save Comment" menu action to allow saving the comments, which is enabled when in "read-only" with "view_comment" mode. Change-Id: I3ab3dbee93ee2167ae96adea7025fc0b385f8201 Reviewed-on: https://gerrit.libreoffice.org/c/online/+/99473 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>feature/calc-canvas
parent
65e3a8de12
commit
ca00470722
|
@ -52,6 +52,7 @@ Session::Session(const std::shared_ptr<ProtocolHandlerInterface> &protocol,
|
|||
_lastActivityTime(std::chrono::steady_clock::now()),
|
||||
_isCloseFrame(false),
|
||||
_isReadOnly(readOnly),
|
||||
_isAllowChangeComments(false),
|
||||
_docPassword(""),
|
||||
_haveDocPassword(false),
|
||||
_isDocPasswordProtected(false),
|
||||
|
|
|
@ -76,9 +76,15 @@ public:
|
|||
const std::string& getName() const { return _name; }
|
||||
bool isDisconnected() const { return _disconnected; }
|
||||
|
||||
virtual void setReadOnly(bool bVal = true) { _isReadOnly = bVal; }
|
||||
virtual void setReadOnly(bool bValue = true) { _isReadOnly = bValue; }
|
||||
bool isReadOnly() const { return _isReadOnly; }
|
||||
|
||||
void setAllowChangeComments(bool bValue = true)
|
||||
{
|
||||
_isAllowChangeComments = bValue;
|
||||
}
|
||||
bool isAllowChangeComments() const { return _isAllowChangeComments; }
|
||||
|
||||
/// overridden to prepend client ids on messages by the Kit
|
||||
virtual bool sendBinaryFrame(const char* buffer, int length);
|
||||
virtual bool sendTextFrame(const char* buffer, const int length);
|
||||
|
@ -249,6 +255,9 @@ private:
|
|||
/// Whether the session is opened as readonly
|
||||
bool _isReadOnly;
|
||||
|
||||
/// If the session is read-only, are comments allowed
|
||||
bool _isAllowChangeComments;
|
||||
|
||||
/// The actual URL, also in the child, even if the child never accesses that.
|
||||
std::string _docURL;
|
||||
|
||||
|
|
|
@ -306,7 +306,7 @@
|
|||
<action name="view" ext="jpeg"/>
|
||||
</app>
|
||||
<app name="application/pdf">
|
||||
<action name="view" ext="pdf"/>
|
||||
<action name="view_comment" ext="pdf"/>
|
||||
</app>
|
||||
|
||||
<app name="Capabilities">
|
||||
|
|
|
@ -254,6 +254,7 @@ L.Control.Menubar = L.Control.extend({
|
|||
{name: _UNO('.uno:PickList', 'presentation'), id: 'file', type: 'menu', menu: [
|
||||
{name: _UNO('.uno:Save', 'presentation'), id: 'save', type: 'action'},
|
||||
{name: _UNO('.uno:SaveAs', 'presentation'), id: 'saveas', type: 'action'},
|
||||
{name: _('Save Comments'), id: 'savecomments', type: 'action'},
|
||||
{name: _('Share...'), id:'shareas', type: 'action'},
|
||||
{name: _UNO('.uno:Print', 'presentation'), id: 'print', type: 'action'},
|
||||
{name: _('See revision history'), id: 'rev-history', type: 'action'},
|
||||
|
@ -725,15 +726,16 @@ L.Control.Menubar = L.Control.extend({
|
|||
commandStates: {},
|
||||
|
||||
// Only these menu options will be visible in readonly mode
|
||||
allowedReadonlyMenus: ['file', 'downloadas', 'view', 'help'],
|
||||
allowedReadonlyMenus: ['file', 'downloadas', 'view', 'insert', 'help'],
|
||||
|
||||
allowedViewModeActions: [
|
||||
'shareas', 'print', // file menu
|
||||
'savecomments', 'shareas', 'print', // file menu
|
||||
'downloadas-pdf', 'downloadas-odt', 'downloadas-doc', 'downloadas-docx', 'downloadas-rtf', 'downloadas-epub', // file menu
|
||||
'downloadas-odp', 'downloadas-ppt', 'downloadas-pptx', 'downloadas-odg', 'print', // file menu
|
||||
'downloadas-ods', 'downloadas-xls', 'downloadas-xlsx', 'closedocument', // file menu
|
||||
'fullscreen', 'zoomin', 'zoomout', 'zoomreset', 'showresolved', // view menu
|
||||
'about', 'keyboard-shortcuts', 'latest-updates', 'online-help', 'report-an-issue' // help menu
|
||||
'about', 'keyboard-shortcuts', 'latest-updates', 'online-help', 'report-an-issue', // help menu
|
||||
'insertcomment'
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -1146,6 +1148,13 @@ L.Control.Menubar = L.Control.extend({
|
|||
}
|
||||
} else if (id === 'saveas') {
|
||||
this._map.fire('postMessage', {msgId: 'UI_SaveAs'});
|
||||
} else if (id === 'savecomments') {
|
||||
if (this._map.isPermissionEditForComments()) {
|
||||
this._map.fire('postMessage', {msgId: 'UI_Save'});
|
||||
if (!this._map._disableDefaultAction['UI_Save']) {
|
||||
this._map.save(false, false);
|
||||
}
|
||||
}
|
||||
} else if (id === 'shareas') {
|
||||
this._map.fire('postMessage', {msgId: 'UI_Share'});
|
||||
} else if (id === 'print') {
|
||||
|
@ -1365,6 +1374,13 @@ L.Control.Menubar = L.Control.extend({
|
|||
}
|
||||
}
|
||||
|
||||
if (this._map.isPermissionEdit()) {
|
||||
switch (menuItem.id) {
|
||||
case 'savecomments':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (menuItem.type === 'action') {
|
||||
if ((menuItem.id === 'rev-history' && !L.Params.revHistoryEnabled) ||
|
||||
(menuItem.id === 'closedocument' && !L.Params.closeButtonEnabled) ||
|
||||
|
|
|
@ -158,7 +158,7 @@ L.Map.include({
|
|||
|
||||
sendUnoCommand: function (command, json) {
|
||||
var isAllowedInReadOnly = false;
|
||||
var allowedCommands = ['.uno:WordCountDialog', '.uno:EditAnnotation', '.uno:InsertAnnotation', '.uno:DeleteAnnotation'];
|
||||
var allowedCommands = ['.uno:Save', '.uno:WordCountDialog', '.uno:EditAnnotation', '.uno:InsertAnnotation', '.uno:DeleteAnnotation'];
|
||||
for (var i in allowedCommands) {
|
||||
if (allowedCommands[i] === command) {
|
||||
isAllowedInReadOnly = true;
|
||||
|
|
|
@ -469,7 +469,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
|
|||
}
|
||||
else if (tokens.equals(0, "save"))
|
||||
{
|
||||
if (isReadOnly())
|
||||
if (isReadOnly() && !isAllowChangeComments())
|
||||
{
|
||||
LOG_WRN("The document is read-only, cannot save.");
|
||||
}
|
||||
|
@ -971,10 +971,16 @@ bool ClientSession::filterMessage(const std::string& message) const
|
|||
}
|
||||
else if (tokens.equals(0, "uno"))
|
||||
{
|
||||
if (tokens.size() > 1 && (tokens.equals(1, ".uno:ExecuteSearch")
|
||||
|| tokens.equals(1, ".uno:EditAnnotation")
|
||||
|| tokens.equals(1, ".uno:InsertAnnotation")
|
||||
|| tokens.equals(1, ".uno:DeleteAnnotation")))
|
||||
if (tokens.size() > 1 && (tokens.equals(1, ".uno:ExecuteSearch")))
|
||||
{
|
||||
allowed = true;
|
||||
}
|
||||
|
||||
if (isAllowChangeComments()
|
||||
&& tokens.size() > 1
|
||||
&& (tokens.equals(1, ".uno:EditAnnotation")
|
||||
|| tokens.equals(1, ".uno:InsertAnnotation")
|
||||
|| tokens.equals(1, ".uno:DeleteAnnotation")))
|
||||
{
|
||||
allowed = true;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ public:
|
|||
void construct();
|
||||
virtual ~ClientSession();
|
||||
|
||||
void setReadOnly(bool bVal = true) override;
|
||||
void setReadOnly(bool bValue = true) override;
|
||||
|
||||
void setLockFailed(const std::string& sReason);
|
||||
|
||||
enum SessionState {
|
||||
|
|
|
@ -633,6 +633,8 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
|
|||
{
|
||||
LOG_DBG("Setting the session as readonly");
|
||||
session->setReadOnly();
|
||||
if (LOOLWSD::IsViewWithCommentsFileExtension(wopiStorage->getFileExtension()))
|
||||
session->setAllowChangeComments();
|
||||
}
|
||||
|
||||
// Construct a JSON containing relevant WOPI host properties
|
||||
|
@ -719,6 +721,8 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
|
|||
{
|
||||
LOG_DBG("Setting the session as readonly");
|
||||
session->setReadOnly();
|
||||
if (LOOLWSD::IsViewWithCommentsFileExtension(localStorage->getFileExtension()))
|
||||
session->setAllowChangeComments();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,7 +210,8 @@ static int careerSpanMs = 0;
|
|||
/// The timeout for a child to spawn, initially high, then reset to the default.
|
||||
int ChildSpawnTimeoutMs = CHILD_TIMEOUT_MS * 4;
|
||||
std::atomic<unsigned> LOOLWSD::NumConnections;
|
||||
std::set<std::string> LOOLWSD::EditFileExtensions;
|
||||
std::unordered_set<std::string> LOOLWSD::EditFileExtensions;
|
||||
std::unordered_set<std::string> LOOLWSD::ViewWithCommentsFileExtensions;
|
||||
|
||||
#if MOBILEAPP
|
||||
|
||||
|
@ -3368,6 +3369,10 @@ private:
|
|||
// Set the View extensions cache as well.
|
||||
if (elem->getAttribute("name") == "edit")
|
||||
LOOLWSD::EditFileExtensions.insert(elem->getAttribute("ext"));
|
||||
else if (elem->getAttribute("name") == "view_comment")
|
||||
{
|
||||
LOOLWSD::ViewWithCommentsFileExtensions.insert(elem->getAttribute("ext"));
|
||||
}
|
||||
}
|
||||
|
||||
const auto& proofAttribs = GetProofKeyAttributes();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <chrono>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
@ -251,7 +252,8 @@ public:
|
|||
#if !MOBILEAPP
|
||||
static std::unique_ptr<ClipboardCache> SavedClipboards;
|
||||
#endif
|
||||
static std::set<std::string> EditFileExtensions;
|
||||
static std::unordered_set<std::string> EditFileExtensions;
|
||||
static std::unordered_set<std::string> ViewWithCommentsFileExtensions;
|
||||
static unsigned MaxConnections;
|
||||
static unsigned MaxDocuments;
|
||||
static std::string OverrideWatermark;
|
||||
|
@ -294,7 +296,7 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
/// Return true iff extension is marked as view action in discovery.xml.
|
||||
/// Return true if extension is marked as view action in discovery.xml.
|
||||
static bool IsViewFileExtension(const std::string& extension)
|
||||
{
|
||||
#if MOBILEAPP
|
||||
|
@ -307,6 +309,19 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
/// Return true if extension is marked as view_comment action in discovery.xml.
|
||||
static bool IsViewWithCommentsFileExtension(const std::string& extension)
|
||||
{
|
||||
#if MOBILEAPP
|
||||
(void) extension;
|
||||
return false; // mark everything editable on mobile
|
||||
#else
|
||||
std::string lowerCaseExtension = extension;
|
||||
std::transform(lowerCaseExtension.begin(), lowerCaseExtension.end(), lowerCaseExtension.begin(), ::tolower);
|
||||
return ViewWithCommentsFileExtensions.find(lowerCaseExtension) != ViewWithCommentsFileExtensions.end();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns the value of the specified application configuration,
|
||||
/// or the default, if one doesn't exist.
|
||||
template<typename T>
|
||||
|
|
Loading…
Reference in New Issue