[Libreoffice-commits] core.git: Branch 'distro/collabora/co-2021' - 15 commits - config_host/config_oauth2.h.in connectivity/source cui/source extensions/source extensions/uiconfig external/libcmis include/svtools officecfg/registry Repository.mk sc/qa sc/source solenv/sanitizers svtools/source svtools/uiconfig svx/source sw/source translations ucb/source
Caolán McNamara (via logerrit)
logerrit at kemper.freedesktop.org
Tue Aug 24 12:51:35 UTC 2021
Rebased ref, commits from common ancestor:
commit ccc30eda6774eb99adc537f9747097e1e8a74b21
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Mon Aug 23 16:55:27 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:53 2021 +0200
rhbz#1996735 SwEditShell::GetCorrection can return null
Though the exact steps to reproduce are unknown. From the text seen in
the backtrace the language is possibly Finnish in which case voikko is
probably the spellchecking backend in use.
Change-Id: I9b3186e4699946235ccc161575bba7d4a3820565
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120879
Reviewed-by: Michael Stahl <michael.stahl at allotropia.de>
Tested-by: Jenkins
diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx
index 7fa40dba919e..7f000e1a59f1 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -1490,7 +1490,9 @@ void SwTextShell::Execute(SfxRequest &rReq)
else if (sApplyText == "Spelling")
{
SwRect aToFill;
- uno::Reference< linguistic2::XSpellAlternatives > xSpellAlt( rWrtSh.GetCorrection(nullptr, aToFill) );
+ uno::Reference<linguistic2::XSpellAlternatives> xSpellAlt(rWrtSh.GetCorrection(nullptr, aToFill));
+ if (!xSpellAlt.is())
+ return;
uno::Reference< linguistic2::XDictionary > xDictionary = LinguMgr::GetIgnoreAllList();
OUString sWord(xSpellAlt->getWord());
linguistic::DictionaryError nAddRes = linguistic::AddEntryToDic( xDictionary,
commit a9d94a12d32f6e2a6bf9c459caa59c8327b64ff5
Author: Christian Lohmaier <lohmaier+LibreOffice at googlemail.com>
AuthorDate: Tue Aug 24 13:48:33 2021 +0200
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:53 2021 +0200
Update git submodules
* Update translations from branch 'distro/collabora/co-2021'
to 96ffb24921d7e554a3a353580b720915a95d2740
- update translations for 7.1.6 rc1
and force-fix errors using pocheck
Change-Id: I01602df1c63103029e3c9198db5e7032addf89c2
- update translations for 7.1.5 rc2
and force-fix errors using pocheck
Change-Id: I42501f3274956b38075932f254e33d4643a3040f
diff --git a/translations b/translations
index 5e70d5e11c07..96ffb24921d7 160000
--- a/translations
+++ b/translations
@@ -1 +1 @@
-Subproject commit 5e70d5e11c077090f4c8d43ca9816842bbdd6c6a
+Subproject commit 96ffb24921d7e554a3a353580b720915a95d2740
commit 16005bc2f2fa01e95d8a4863e336cac96a78433e
Author: Christian Lohmaier <lohmaier+LibreOffice at googlemail.com>
AuthorDate: Tue Feb 16 14:07:34 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:53 2021 +0200
tdf#101630 - gdrive support w/oAuth and Drive API v3
LibreOffice is only using drive.file scope, so can only see files it
owns/that were created by LibreOffice.
In addition, also store the refresh token in LO's password-store if the
user enabled persistent storage, removing the need to to the
copy'n'paste dance to grant access each time LO is launched.
related tdf#115643 also store the refresh token for onedrive
consolidate the fallback-auth provides for onedrive/gdrive into one,
they are all the same login in browser, then copy code method that
ultimately should be changed to having LO listen on local port for the
code
Change-Id: I97e3843682c302d2884e35ece6e72bc3a07e2539
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119572
Tested-by: Jenkins
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice at googlemail.com>
(cherry picked from commit 73041de9563c9a973d1b5394c6e5520a7d799980)
fix install with --disable-cmis
Change-Id: I51430a860a0b5047b566ed8184f0f563ec54f288
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119661
Tested-by: Jenkins
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice at googlemail.com>
(cherry picked from commit 299b72e4c9ad239d747e47eaf004400f5a590695)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120544
diff --git a/Repository.mk b/Repository.mk
index e056cbfce29f..2149816fe461 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -432,7 +432,7 @@ $(eval $(call gb_Helper_register_libraries_for_install,OOOLIBS,ooo, \
ucpexpand1 \
ucpext \
ucpimage \
- ucpcmis1 \
+ $(if $(ENABLE_LIBCMIS),ucpcmis1) \
ucptdoc1 \
unordf \
unoxml \
diff --git a/config_host/config_oauth2.h.in b/config_host/config_oauth2.h.in
index a95015b41f3e..9945dda3dda5 100644
--- a/config_host/config_oauth2.h.in
+++ b/config_host/config_oauth2.h.in
@@ -15,13 +15,13 @@
/* Google Drive settings */
-#define GDRIVE_BASE_URL "https://www.googleapis.com/drive/v2"
+#define GDRIVE_BASE_URL "https://www.googleapis.com/drive/v3"
#define GDRIVE_CLIENT_ID ""
#define GDRIVE_CLIENT_SECRET ""
-#define GDRIVE_AUTH_URL "https://accounts.google.com/o/oauth2/auth"
-#define GDRIVE_TOKEN_URL "https://accounts.google.com/o/oauth2/token"
+#define GDRIVE_AUTH_URL "https://accounts.google.com/o/oauth2/v2/auth"
+#define GDRIVE_TOKEN_URL "https://oauth2.googleapis.com/token"
#define GDRIVE_REDIRECT_URI "urn:ietf:wg:oauth:2.0:oob"
-#define GDRIVE_SCOPE "https://www.googleapis.com/auth/drive"
+#define GDRIVE_SCOPE "https://www.googleapis.com/auth/drive.file"
/* Alfresco Cloud */
diff --git a/external/libcmis/UnpackedTarball_libcmis.mk b/external/libcmis/UnpackedTarball_libcmis.mk
index a5be3078c95a..8398853e4511 100644
--- a/external/libcmis/UnpackedTarball_libcmis.mk
+++ b/external/libcmis/UnpackedTarball_libcmis.mk
@@ -17,6 +17,8 @@ $(eval $(call gb_UnpackedTarball_add_patches,libcmis, \
external/libcmis/libcmis-libxml2_compatibility.patch \
external/libcmis/0001-rename-class-GetObject-to-avoid-name-clash-on-Window.patch \
external/libcmis/libcmis_onedrive.patch \
+ external/libcmis/libcmis_oauth_pw_as_refreshtoken.patch.1 \
+ external/libcmis/libcmis_gdrive.patch.1 \
))
# vim: set noet sw=4 ts=4:
diff --git a/external/libcmis/libcmis_gdrive.patch.1 b/external/libcmis/libcmis_gdrive.patch.1
new file mode 100644
index 000000000000..24ff65d1ef15
--- /dev/null
+++ b/external/libcmis/libcmis_gdrive.patch.1
@@ -0,0 +1,702 @@
+diff -ur libcmis.org/src/libcmis/gdrive-document.cxx libcmis/src/libcmis/gdrive-document.cxx
+--- libcmis.org/src/libcmis/gdrive-document.cxx 2021-07-27 19:11:02.679247008 +0200
++++ libcmis/src/libcmis/gdrive-document.cxx 2021-07-27 19:11:18.873246420 +0200
+@@ -145,23 +145,17 @@
+ {
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+- if ( !isImmutable( ) )
+- throw libcmis::Exception( string ( "Document " + getId( )+
+- " is not editable" ) );
+- string putUrl = getUploadUrl( ) + getId( );
+- putUrl += "?uploadType=media";
+-
+- // If it's a Google document, convert it
+- if ( isGoogleDoc( ) )
+- putUrl += "&convert=true";
++
++ string putUrl = GDRIVE_UPLOAD_LINK + getId( ) + "?uploadType=media";
+
+ // Upload stream
+ boost::shared_ptr< istream> is ( new istream ( os->rdbuf( ) ) );
+ vector <string> headers;
+ headers.push_back( string( "Content-Type: " ) + contentType );
++ string res;
+ try
+ {
+- getSession()->httpPutRequest( putUrl, *is, headers );
++ res = getSession()->httpPatchRequest( putUrl, *is, headers )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+@@ -181,35 +175,10 @@
+ {
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+-
+- if ( !isImmutable( ) )
+- throw libcmis::Exception( string ( "Document " + getId( )+
+- " is not editable" ) );
+- string metaUrl = getUrl( );
+-
+- // If it's a Google document, convert it
+- if ( isGoogleDoc( ) )
+- metaUrl += "?convert=true";
+-
+- // Update file name meta information
+- if ( !fileName.empty( ) && fileName != getContentFilename( ) )
+- {
+- Json metaJson;
+- Json fileJson( fileName.c_str( ) );
+- metaJson.add("title", fileJson );
+-
+- std::istringstream is( metaJson.toString( ) );
+- vector<string> headers;
+- headers.push_back( "Content-Type: application/json" );
+- try
+- {
+- getSession()->httpPutRequest( metaUrl, is, headers );
+- }
+- catch ( const CurlException& e )
+- {
+- throw e.getCmisException( );
+- }
+- }
++
++ // TODO: when would the filename need an update?
++ if (!fileName.empty() && fileName != getContentFilename())
++ std::cout << "filename change is not implemented in setContentStream" << std::endl;
+
+ // Upload stream
+ uploadStream( os, contentType );
+@@ -251,7 +220,7 @@
+ vector< libcmis::DocumentPtr > GDriveDocument::getAllVersions( )
+ {
+ vector< libcmis::DocumentPtr > revisions;
+- string versionUrl = getUrl( ) + "/revisions";
++ string versionUrl = GDRIVE_METADATA_LINK + getId( ) + "/revisions";
+ // Run the http request to get the properties definition
+ string res;
+ try
+@@ -263,7 +232,7 @@
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+- Json::JsonVector objs = jsonRes["items"].getList( );
++ Json::JsonVector objs = jsonRes["revisions"].getList( );
+
+ string parentId = getStringProperty( "cmis:parentId" );
+
+diff -ur libcmis.org/src/libcmis/gdrive-folder.cxx libcmis/src/libcmis/gdrive-folder.cxx
+--- libcmis.org/src/libcmis/gdrive-folder.cxx 2021-07-27 19:11:02.678247008 +0200
++++ libcmis/src/libcmis/gdrive-folder.cxx 2021-07-27 19:11:18.874246420 +0200
+@@ -62,8 +62,8 @@
+ // Instead of sending multiple queries for children,
+ // we send a single query to search for objects where parents
+ // include the folderID.
+- string query = getSession( )->getBindingUrl( ) +
+- "/files?q=\"" + getId( ) + "\"+in+parents+and+trashed+=+false";
++ string query = GDRIVE_METADATA_LINK + "?q=\"" + getId( ) + "\"+in+parents+and+trashed+=+false" +
++ "&fields=files(kind,id,name,parents,mimeType,createdTime,modifiedTime,thumbnailLink,size)";
+
+ string res;
+ try
+@@ -76,7 +76,7 @@
+ }
+
+ Json jsonRes = Json::parse( res );
+- Json::JsonVector objs = jsonRes["items"].getList( );
++ Json::JsonVector objs = jsonRes["files"].getList( );
+
+ // Create children objects from Json objects
+ for(unsigned int i = 0; i < objs.size(); i++)
+@@ -95,7 +95,7 @@
+ string GDriveFolder::uploadProperties( Json properties )
+ {
+ // URL for uploading meta data
+- string metaUrl = getSession()->getBindingUrl() + "/files/";
++ string metaUrl = GDRIVE_METADATA_LINK + "?fields=kind,id,name,parents,mimeType,createdTime,modifiedTime";
+
+ // add parents to the properties
+ properties.add( "parents", GdriveUtils::createJsonFromParentId( getId( ) ) );
+@@ -147,9 +147,15 @@
+
+ Json propsJson = GdriveUtils::toGdriveJson( properties );
+
+- // Add filename to properties
+- Json jsonFilename( fileName.c_str( ) );
+- propsJson.add( "title", jsonFilename );
++ if(!fileName.empty()) {
++ // use provided filename
++ Json jsonFilename( fileName.c_str( ) );
++
++ propsJson.add( "name", jsonFilename );
++ }
++ if(!contentType.empty()) {
++ propsJson.add( "mimeType", Json(contentType.c_str()));
++ }
+
+ // Upload meta-datas
+ string res = uploadProperties( propsJson);
+@@ -171,12 +177,9 @@
+ libcmis::UnfileObjects::Type /*unfile*/,
+ bool /*continueOnError*/ )
+ {
+- // Object remove doesn't work with folder
+- // Using trash instead
+ try
+ {
+- istringstream is( "" );
+- getSession( )->httpPostRequest( getUrl( ) + "/trash", is, "" );
++ getSession( )->httpDeleteRequest( GDRIVE_METADATA_LINK + getId( ) );
+ }
+ catch ( const CurlException& e )
+ {
+diff -ur libcmis.org/src/libcmis/gdrive-object.cxx libcmis/src/libcmis/gdrive-object.cxx
+--- libcmis.org/src/libcmis/gdrive-object.cxx 2021-07-27 19:11:02.675247009 +0200
++++ libcmis/src/libcmis/gdrive-object.cxx 2021-07-27 19:11:18.874246420 +0200
+@@ -89,8 +89,8 @@
+ property.reset( new GDriveProperty( it->first, it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+
+- // we map "title" to both "cmis:name" and "cmis:getContentStreamFileName"
+- if ( it->first == "title" )
++ // we map "name" to both "cmis:name" and "cmis:getContentStreamFileName"
++ if ( it->first == "name" )
+ {
+ property.reset( new GDriveProperty( "cmis:name", it->second) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+@@ -142,16 +142,13 @@
+ {
+ if ( m_renditions.empty( ) )
+ {
+- string downloadUrl = getStringProperty( "downloadUrl" );
+- if ( !downloadUrl.empty( ) )
+- {
+- string mimeType = getStringProperty( "cmis:contentStreamMimeType" );
+- if ( !mimeType.empty( ) )
+- {
+- RenditionPtr rendition(
+- new Rendition( mimeType, mimeType, mimeType, downloadUrl ));
+- m_renditions.push_back( rendition );
+- }
++ string downloadUrl = GDRIVE_METADATA_LINK + getId( ) + "?alt=media";
++ string mimeType = getStringProperty( "cmis:contentStreamMimeType" );
++ if ( !mimeType.empty( ) )
++ {
++ RenditionPtr rendition(
++ new Rendition( mimeType, mimeType, mimeType, downloadUrl ));
++ m_renditions.push_back( rendition );
+ }
+
+ vector< string > exportLinks = getMultiStringProperty( "exportLinks" );
+@@ -192,7 +189,7 @@
+ {
+ vector< string > headers;
+ headers.push_back( "Content-Type: application/json" );
+- response = getSession( )->httpPutRequest( getUrl( ), is, headers );
++ response = getSession( )->httpPatchRequest( getUrl( ), is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+@@ -228,7 +225,7 @@
+ {
+ try
+ {
+- getSession( )->httpDeleteRequest( getUrl( ) );
++ getSession( )->httpDeleteRequest( GDRIVE_METADATA_LINK + getId( ) );
+ }
+ catch ( const CurlException& e )
+ {
+@@ -239,8 +236,8 @@
+ void GDriveObject::move( FolderPtr /*source*/, FolderPtr destination )
+ {
+ Json parentsJson;
+- Json parentsValue = GdriveUtils::createJsonFromParentId( destination->getId( ) );
+- parentsJson.add( "parents", parentsValue );
++ parentsJson.add( "addParents", Json(destination->getId( ).c_str()) );
++ parentsJson.add( "removeParents", Json(getStringProperty( "cmis:parentId" ).c_str()) );
+
+ istringstream is( parentsJson.toString( ) );
+ libcmis::HttpResponsePtr response;
+@@ -248,7 +245,7 @@
+ {
+ vector< string > headers;
+ headers.push_back( "Content-Type: application/json" );
+- response = getSession( )->httpPutRequest( getUrl( ), is, headers );
++ response = getSession( )->httpPatchRequest( getUrl( ), is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+@@ -262,12 +259,10 @@
+
+ string GDriveObject::getUrl( )
+ {
+- return getSession( )->getBindingUrl( ) + "/files/" + getId( );
+-}
+-
+-string GDriveObject::getUploadUrl( )
+-{
+- return GDRIVE_UPLOAD_LINKS;
++ // thumbnailLink causes some operations to fail with internal server error,
++ // see https://issuetracker.google.com/issues/36760667
++ return GDRIVE_METADATA_LINK + getId( ) +
++ "?fields=kind,id,name,parents,mimeType,createdTime,modifiedTime,size";
+ }
+
+ vector< string> GDriveObject::getMultiStringProperty( const string& propertyName )
+diff -ur libcmis.org/src/libcmis/gdrive-repository.cxx libcmis/src/libcmis/gdrive-repository.cxx
+--- libcmis.org/src/libcmis/gdrive-repository.cxx 2021-07-27 19:11:02.676247009 +0200
++++ libcmis/src/libcmis/gdrive-repository.cxx 2021-07-27 19:11:18.874246420 +0200
+@@ -35,7 +35,7 @@
+ m_name = "Google Drive";
+ m_description = "Google Drive repository";
+ m_productName = "Google Drive";
+- m_productVersion = "v2";
++ m_productVersion = "v3";
+ m_rootId = "root";
+
+ m_capabilities[ ACL ] = "discover";
+diff -ur libcmis.org/src/libcmis/gdrive-session.cxx libcmis/src/libcmis/gdrive-session.cxx
+--- libcmis.org/src/libcmis/gdrive-session.cxx 2021-07-27 19:11:02.675247009 +0200
++++ libcmis/src/libcmis/gdrive-session.cxx 2021-07-27 19:11:18.874246420 +0200
+@@ -124,9 +124,13 @@
+
+ libcmis::ObjectPtr GDriveSession::getObject( string objectId )
+ {
++ if(objectId == "root") {
++ return getRootFolder();
++ }
+ // Run the http request to get the properties definition
+ string res;
+- string objectLink = m_bindingUrl + "/files/" + objectId;
++ string objectLink = GDRIVE_METADATA_LINK + objectId +
++ "?fields=kind,id,name,parents,mimeType,createdTime,modifiedTime,thumbnailLink,size";
+ try
+ {
+ res = httpGetRequest( objectLink )->getStream()->str();
+@@ -188,9 +192,10 @@
+ {
+ // Normal child case
+ // Ask for the ID of the child if there is any
+- string childIdUrl = m_bindingUrl + "/files/" + objectId +
+- "/children/?q=title+=+'" + segment +
+- "'&fields=items:id";
++ // somewhat flawed as names are not necessarily unique in GDrive...
++ string query = libcmis::escape("'" + objectId + "' in parents and trashed = false and name='" + segment + "'");
++
++ string childIdUrl = m_bindingUrl + "/files/?q=" + query + "&fields=files(id)";
+
+ string res;
+ try
+@@ -204,7 +209,7 @@
+ Json jsonRes = Json::parse( res );
+
+ // Did we get an id?
+- Json::JsonVector items = jsonRes["items"].getList();
++ Json::JsonVector items = jsonRes["files"].getList();
+ if ( items.empty( ) )
+ throw libcmis::Exception( "Object not found: " + path, "objectNotFound" );
+
+@@ -219,6 +224,27 @@
+ return getObject( objectId );
+ }
+
++libcmis::FolderPtr GDriveSession::getRootFolder()
++{
++ // permissions/scope with just drive.file don't allow to get it with the "root" alias/by its actual object-ID
++ Json propsJson;
++
++ // GDrive folder is a file with a different mime type.
++ string mimeType = GDRIVE_FOLDER_MIME_TYPE;
++
++ // Add mimetype to the propsJson
++ Json jsonMimeType( mimeType.c_str( ) );
++ propsJson.add( "mimeType", jsonMimeType );
++ propsJson.add( "id", "root" );
++
++ // Upload meta-datas
++ propsJson.add("cmis:name", "VirtualRoot");
++
++ libcmis::FolderPtr folderPtr( new GDriveFolder( this, propsJson ) );
++
++ return folderPtr;
++}
++
+ libcmis::ObjectTypePtr GDriveSession::getType( string id )
+ {
+ libcmis::ObjectTypePtr type( new GdriveObjectType( id ) );
+diff -ur libcmis.org/src/libcmis/gdrive-session.hxx libcmis/src/libcmis/gdrive-session.hxx
+--- libcmis.org/src/libcmis/gdrive-session.hxx 2021-07-27 19:11:02.675247009 +0200
++++ libcmis/src/libcmis/gdrive-session.hxx 2021-07-27 19:11:18.875246420 +0200
+@@ -57,6 +57,8 @@
+
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+
++ virtual libcmis::FolderPtr getRootFolder();
++
+ virtual std::string getRefreshToken();
+
+ private:
+diff -ur libcmis.org/src/libcmis/gdrive-utils.cxx libcmis/src/libcmis/gdrive-utils.cxx
+--- libcmis.org/src/libcmis/gdrive-utils.cxx 2021-07-27 19:11:02.677247008 +0200
++++ libcmis/src/libcmis/gdrive-utils.cxx 2021-07-27 19:11:18.875246420 +0200
+@@ -44,17 +44,17 @@
+ convertedKey = "cmis:createdBy";
+ else if ( key == "description" )
+ convertedKey = "cmis:description";
+- else if ( key == "createdDate" )
++ else if ( key == "createdTime" )
+ convertedKey = "cmis:creationDate";
+ else if ( key == "lastModifyingUserName" )
+ convertedKey = "cmis:lastModifiedBy";
+- else if ( key == "modifiedDate" )
++ else if ( key == "modifiedTime" )
+ convertedKey = "cmis:lastModificationDate";
+- else if ( key == "title" )
++ else if ( key == "name" )
+ convertedKey = "cmis:contentStreamFileName";
+ else if ( key == "mimeType" )
+ convertedKey = "cmis:contentStreamMimeType";
+- else if ( key == "fileSize" )
++ else if ( key == "size" )
+ convertedKey = "cmis:contentStreamLength";
+ else if ( key == "editable" )
+ convertedKey = "cmis:isImmutable";
+@@ -72,21 +72,21 @@
+ else if ( key == "cmis:createdBy" )
+ convertedKey = "ownerNames";
+ else if ( key == "cmis:creationDate" )
+- convertedKey = "createdDate";
++ convertedKey = "createdTime";
+ else if ( key == "cmis:description" )
+ convertedKey = "description";
+ else if ( key == "cmis:lastModifiedBy" )
+ convertedKey = "lastModifyingUserName";
+ else if ( key == "cmis:lastModificationDate" )
+- convertedKey = "modifiedDate";
++ convertedKey = "modifiedTime";
+ else if ( key == "cmis:contentStreamFileName" )
+- convertedKey = "title";
++ convertedKey = "name";
+ else if ( key == "cmis:name" )
+- convertedKey = "title";
++ convertedKey = "name";
+ else if ( key == "cmis:contentStreamMimeType" )
+ convertedKey = "mimeType";
+ else if ( key == "cmis:contentStreamLength" )
+- convertedKey = "fileSize";
++ convertedKey = "size";
+ else if ( key == "cmis:isImmutable" )
+ convertedKey = "editable";
+ else if ( key == "cmis:parentId" )
+@@ -124,9 +124,9 @@
+ bool GdriveUtils::checkUpdatable( const string& key )
+ {
+ // taken from https://developers.google.com/drive/v2/reference/files
+- bool updatable = ( key == "title" ||
++ bool updatable = ( key == "name" ||
+ key == "description" ||
+- key == "modifiedDate" ||
++ key == "modifiedTime" ||
+ key == "lastViewedByMeDate" );
+ return updatable;
+ }
+@@ -143,18 +143,11 @@
+
+ Json GdriveUtils::createJsonFromParentId( const string& parentId )
+ {
+- Json parentValue( parentId.c_str( ) );
+-
+ // parents is a Json array
+ Json firstParent;
+- firstParent.add( "id", parentValue );
+-
+- Json::JsonVector parents;
+- parents.insert( parents.begin( ), firstParent );
++ firstParent.add( Json( parentId.c_str() ) );
+
+- Json parentsValue( parents );
+-
+- return parentsValue;
++ return firstParent;
+ }
+
+ vector< string > GdriveUtils::parseGdriveProperty( string key, Json json )
+diff -ur libcmis.org/src/libcmis/gdrive-utils.hxx libcmis/src/libcmis/gdrive-utils.hxx
+--- libcmis.org/src/libcmis/gdrive-utils.hxx 2021-07-27 19:11:02.677247008 +0200
++++ libcmis/src/libcmis/gdrive-utils.hxx 2021-07-27 19:11:18.875246420 +0200
+@@ -35,7 +35,8 @@
+ #include "json-utils.hxx"
+
+ static const std::string GDRIVE_FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" ;
+-static const std::string GDRIVE_UPLOAD_LINKS = "https://www.googleapis.com/upload/drive/v2/files/";
++static const std::string GDRIVE_UPLOAD_LINK = "https://www.googleapis.com/upload/drive/v3/files/";
++static const std::string GDRIVE_METADATA_LINK = "https://www.googleapis.com/drive/v3/files/";
+
+ class GdriveUtils
+ {
+diff -ur libcmis.org/src/libcmis/oauth2-handler.cxx libcmis/src/libcmis/oauth2-handler.cxx
+--- libcmis.org/src/libcmis/oauth2-handler.cxx 2021-07-27 19:11:02.676247009 +0200
++++ libcmis/src/libcmis/oauth2-handler.cxx 2021-07-27 19:11:18.875246420 +0200
+@@ -92,8 +92,11 @@
+ "code=" + authCode +
+ "&client_id=" + m_data->getClientId() +
+ "&redirect_uri=" + m_data->getRedirectUri() +
+- "&scope=" + libcmis::escape( m_data->getScope() ) +
+ "&grant_type=authorization_code" ;
++ if(boost::starts_with(m_data->getTokenUrl(), "https://oauth2.googleapis.com/"))
++ post += "&client_secret=" + m_data->getClientSecret();
++ else
++ post += "&scope=" + libcmis::escape( m_data->getScope() );
+
+ istringstream is( post );
+
+@@ -104,7 +107,7 @@
+ resp = m_session->httpPostRequest ( m_data->getTokenUrl(), is,
+ "application/x-www-form-urlencoded" );
+ }
+- catch ( const CurlException& )
++ catch ( const CurlException& e)
+ {
+ throw libcmis::Exception(
+ "Couldn't get tokens from the authorization code ");
+@@ -122,6 +125,8 @@
+ "refresh_token=" + m_refresh +
+ "&client_id=" + m_data->getClientId() +
+ "&grant_type=refresh_token" ;
++ if(boost::starts_with(m_data->getTokenUrl(), "https://oauth2.googleapis.com/"))
++ post += "&client_secret=" + m_data->getClientSecret();
+
+ istringstream is( post );
+ libcmis::HttpResponsePtr resp;
+@@ -130,7 +135,7 @@
+ resp = m_session->httpPostRequest( m_data->getTokenUrl( ), is,
+ "application/x-www-form-urlencoded" );
+ }
+- catch (const CurlException& )
++ catch (const CurlException& e )
+ {
+ throw libcmis::Exception( "Couldn't refresh token ");
+ }
+diff -ur libcmis.org/src/libcmis/oauth2-providers.cxx libcmis/src/libcmis/oauth2-providers.cxx
+--- libcmis.org/src/libcmis/oauth2-providers.cxx 2021-07-27 19:11:02.679247008 +0200
++++ libcmis/src/libcmis/oauth2-providers.cxx 2021-07-27 19:11:18.886246420 +0200
+@@ -80,172 +80,8 @@
+
+ }
+
+-string OAuth2Providers::OAuth2Gdrive( HttpSession* session, const string& authUrl,
+- const string& username, const string& password )
+-{
+- /* This member function implements 'Google OAuth 2.0'
+- *
+- * The interaction is carried out by libcmis, with no web browser involved.
+- *
+- * Normal sequence (without 2FA) is:
+- * 1) a get to activate login page
+- * receive first login page, html format
+- * 2) subsequent post to sent email
+- * receive html page for password input
+- * 3) subsequent post to send password
+- * receive html page for application consent
+- * 4) subsequent post to send a consent for the application
+- * receive a single-use authorization code
+- * this code is returned as a string
+- *
+- * Sequence with 2FA is:
+- * 1) a get to activate login page
+- * receive first login page, html format
+- * 2) subsequent post to sent email
+- * receive html page for password input
+- * 3) subsequent post to send password
+- * receive html page for pin input
+- * 3b) subsequent post to send pin number
+- * receive html page for application consent
+- * 4) subsequent post to send a consent for the application
+- * receive a single-use authorization code
+- * this code is returned as a string
+- */
+-
+- static const string CONTENT_TYPE( "application/x-www-form-urlencoded" );
+- // STEP 1: get login page
+- string res;
+- try
+- {
+- // send the first get, receive the html login page
+- res = session->httpGetRequest( authUrl )->getStream( )->str( );
+- }
+- catch ( const CurlException& )
+- {
+- return string( );
+- }
+-
+- // STEP 2: send email
+-
+- string loginEmailPost, loginEmailLink;
+- if ( !parseResponse( res.c_str( ), loginEmailPost, loginEmailLink ) )
+- return string( );
+-
+- loginEmailPost += "Email=";
+- loginEmailPost += escapeForm( username );
+-
+- istringstream loginEmailIs( loginEmailPost );
+- string loginEmailRes;
+- try
+- {
+- // send a post with user email, receive the html page for password input
+- loginEmailRes = session->httpPostRequest ( loginEmailLink, loginEmailIs, CONTENT_TYPE )
+- ->getStream( )->str( );
+- }
+- catch ( const CurlException& )
+- {
+- return string( );
+- }
+-
+- // STEP 3: password page
+-
+- string loginPasswdPost, loginPasswdLink;
+- if ( !parseResponse( loginEmailRes.c_str( ), loginPasswdPost, loginPasswdLink ) )
+- return string( );
+-
+- loginPasswdPost += "Passwd=";
+- loginPasswdPost += escapeForm( password );
+-
+- istringstream loginPasswdIs( loginPasswdPost );
+- string loginPasswdRes;
+- try
+- {
+- // send a post with user password, receive the application consent page
+- loginPasswdRes = session->httpPostRequest ( loginPasswdLink, loginPasswdIs, CONTENT_TYPE )
+- ->getStream( )->str( );
+- }
+- catch ( const CurlException& )
+- {
+- return string( );
+- }
+-
+- string approvalPost, approvalLink;
+- if ( !parseResponse( loginPasswdRes. c_str( ), approvalPost, approvalLink) )
+- return string( );
+-
+- // when 2FA is enabled, link doesn't start with 'http'
+- if ( approvalLink.compare(0, 4, "http") != 0 )
+- {
+- // STEP 3b: 2 Factor Authentication, pin code request
+-
+- string loginChallengePost( approvalPost );
+- string loginChallengeLink( approvalLink );
+-
+- libcmis::OAuth2AuthCodeProvider fallbackProvider = libcmis::SessionFactory::getOAuth2AuthCodeProvider( );
+- unique_ptr< char, void (*)( void * ) > pin{ fallbackProvider( "", "", "" ), free };
+-
+- if( !pin )
+- {
+- // unset OAuth2AuthCode Provider to avoid showing pin request again in the HttpSession::oauth2Authenticate
+- libcmis::SessionFactory::setOAuth2AuthCodeProvider( NULL );
+- return string( );
+- }
+-
+- loginChallengeLink = "https://accounts.google.com" + loginChallengeLink;
+- loginChallengePost += string( PIN_INPUT_NAME ) + "=";
+- loginChallengePost += string( pin.get() );
+-
+- istringstream loginChallengeIs( loginChallengePost );
+- string loginChallengeRes;
+- try
+- {
+- // send a post with pin, receive the application consent page
+- loginChallengeRes = session->httpPostRequest ( loginChallengeLink, loginChallengeIs, CONTENT_TYPE )
+- ->getStream( )->str( );
+- }
+- catch ( const CurlException& )
+- {
+- return string( );
+- }
+-
+- approvalPost = string();
+- approvalLink = string();
+-
+- if ( !parseResponse( loginChallengeRes. c_str( ), approvalPost, approvalLink) )
+- return string( );
+- }
+- else if( approvalLink.compare( "https://accounts.google.com/ServiceLoginAuth" ) == 0 )
+- {
+- // wrong password,
+- // unset OAuth2AuthCode Provider to avoid showing pin request again in the HttpSession::oauth2Authenticate
+- libcmis::SessionFactory::setOAuth2AuthCodeProvider( NULL );
+- return string( );
+- }
+-
+- // STEP 4: allow libcmis to access google drive
+- approvalPost += "submit_access=true";
+-
+- istringstream approvalIs( approvalPost );
+- string approvalRes;
+- try
+- {
+- // send a post with application consent
+- approvalRes = session->httpPostRequest ( approvalLink, approvalIs,
+- CONTENT_TYPE) ->getStream( )->str( );
+- }
+- catch ( const CurlException& e )
+- {
+- throw e.getCmisException( );
+- }
+-
+- // Take the authentication code from the text bar
+- string code = parseCode( approvalRes.c_str( ) );
+-
+- return code;
+-}
+-
+-string OAuth2Providers::OAuth2Onedrive( HttpSession* /*session*/, const string& /*authUrl*/,
+- const string& /*username*/, const string& /*password*/ )
++string OAuth2Providers::OAuth2Dummy( HttpSession* /*session*/, const string& /*authUrl*/,
++ const string& /*username*/, const string& /*password*/ )
+ {
+ return string( );
+ }
+@@ -314,12 +150,8 @@
+ // For Alfresco in the cloud, only match the hostname as there can be several
+ // binding URLs created with it.
+ return OAuth2Alfresco;
+- else if ( boost::starts_with( url, "https://www.googleapis.com/drive/v2" ) )
+- return OAuth2Gdrive;
+- else if ( boost::starts_with( url, "https://graph.microsoft.com/v1.0" ) )
+- return OAuth2Onedrive;
+
+- return OAuth2Gdrive;
++ return OAuth2Dummy;
+ }
+
+ int OAuth2Providers::parseResponse ( const char* response, string& post, string& link )
+diff -ur libcmis.org/src/libcmis/oauth2-providers.hxx libcmis/src/libcmis/oauth2-providers.hxx
+--- libcmis.org/src/libcmis/oauth2-providers.hxx 2021-07-27 19:11:02.678247008 +0200
++++ libcmis/src/libcmis/oauth2-providers.hxx 2021-07-27 19:11:18.886246420 +0200
+@@ -39,12 +39,8 @@
+ class OAuth2Providers
+ {
+ public :
+- static std::string OAuth2Gdrive( HttpSession* session, const std::string& authUrl,
++ static std::string OAuth2Dummy( HttpSession* session, const std::string& authUrl,
+ const std::string& username, const std::string& password );
+-
+- static std::string OAuth2Onedrive( HttpSession* session, const std::string& authUrl,
+- const std::string& username, const std::string& password );
+-
+ static std::string OAuth2Alfresco( HttpSession* session, const std::string& authUrl,
+ const std::string& username, const std::string& password );
+
+diff -ur libcmis.org/src/libcmis/session-factory.cxx libcmis/src/libcmis/session-factory.cxx
+--- libcmis.org/src/libcmis/session-factory.cxx 2021-07-27 19:11:02.679247008 +0200
++++ libcmis/src/libcmis/session-factory.cxx 2021-07-27 19:11:18.886246420 +0200
+@@ -66,7 +66,7 @@
+ if ( !bindingUrl.empty( ) )
+ {
+ // Try the special cases based on the binding URL
+- if ( bindingUrl == "https://www.googleapis.com/drive/v2" )
++ if ( bindingUrl == "https://www.googleapis.com/drive/v3" )
+ {
+ session = new GDriveSession( bindingUrl, username, password,
+ oauth2, verbose );
diff --git a/external/libcmis/libcmis_oauth_pw_as_refreshtoken.patch.1 b/external/libcmis/libcmis_oauth_pw_as_refreshtoken.patch.1
new file mode 100644
index 000000000000..a8cb06509421
--- /dev/null
+++ b/external/libcmis/libcmis_oauth_pw_as_refreshtoken.patch.1
@@ -0,0 +1,185 @@
+diff -ur libcmis.org/inc/libcmis/session.hxx libcmis/inc/libcmis/session.hxx
+--- libcmis.org/inc/libcmis/session.hxx 2021-07-27 19:09:42.580249917 +0200
++++ libcmis/inc/libcmis/session.hxx 2021-07-27 19:10:02.368249199 +0200
+@@ -95,6 +95,8 @@
+ certificate exception feature available on common web browser.
+ */
+ virtual void setNoSSLCertificateCheck( bool noCheck ) = 0;
++
++ virtual std::string getRefreshToken() { return ""; };
+ };
+ }
+
+diff -ur libcmis.org/src/libcmis/gdrive-session.cxx libcmis/src/libcmis/gdrive-session.cxx
+--- libcmis.org/src/libcmis/gdrive-session.cxx 2021-07-27 19:09:42.581249917 +0200
++++ libcmis/src/libcmis/gdrive-session.cxx 2021-07-27 19:10:02.369249198 +0200
+@@ -70,6 +70,46 @@
+ {
+ }
+
++
++void GDriveSession::setOAuth2Data( libcmis::OAuth2DataPtr oauth2 )
++{
++ m_oauth2Handler = new OAuth2Handler( this, oauth2 );
++ m_oauth2Handler->setOAuth2Parser( OAuth2Providers::getOAuth2Parser( getBindingUrl( ) ) );
++
++ oauth2Authenticate( );
++}
++
++void GDriveSession::oauth2Authenticate()
++{
++ // treat the supplied password as refresh token
++ if (!m_password.empty())
++ {
++ try
++ {
++ m_inOAuth2Authentication = true;
++
++ m_oauth2Handler->setRefreshToken(m_password);
++ // Try to get new access tokens using the stored refreshtoken
++ m_oauth2Handler->refresh();
++ m_inOAuth2Authentication = false;
++ }
++ catch (const CurlException &e)
++ {
++ m_inOAuth2Authentication = false;
++ // refresh token expired or invalid, trigger initial auth (that in turn will hit the fallback with copy'n'paste method)
++ BaseSession::oauth2Authenticate();
++ }
++ }
++ else
++ {
++ BaseSession::oauth2Authenticate();
++ }
++}
++
++string GDriveSession::getRefreshToken() {
++ return HttpSession::getRefreshToken();
++}
++
+ libcmis::RepositoryPtr GDriveSession::getRepository( )
+ {
+ // Return a dummy repository since GDrive doesn't have that notion
+diff -ur libcmis.org/src/libcmis/gdrive-session.hxx libcmis/src/libcmis/gdrive-session.hxx
+--- libcmis.org/src/libcmis/gdrive-session.hxx 2021-07-27 19:09:42.583249917 +0200
++++ libcmis/src/libcmis/gdrive-session.hxx 2021-07-27 19:10:02.369249198 +0200
+@@ -57,8 +57,14 @@
+
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+
++ virtual std::string getRefreshToken();
++
+ private:
+ GDriveSession( );
++
++ virtual void setOAuth2Data( libcmis::OAuth2DataPtr oauth2 );
++
++ void oauth2Authenticate( );
+ };
+
+ #endif /* _GDRIVE_SESSION_HXX_ */
+diff -ur libcmis.org/src/libcmis/http-session.hxx libcmis/src/libcmis/http-session.hxx
+--- libcmis.org/src/libcmis/http-session.hxx 2021-07-27 19:09:42.582249917 +0200
++++ libcmis/src/libcmis/http-session.hxx 2021-07-27 19:10:02.369249198 +0200
+@@ -148,7 +148,7 @@
+
+ void setNoSSLCertificateCheck( bool noCheck );
+
+- std::string getRefreshToken( );
++ virtual std::string getRefreshToken( );
+
+ protected:
+ HttpSession( );
+diff -ur libcmis.org/src/libcmis/oauth2-handler.cxx libcmis/src/libcmis/oauth2-handler.cxx
+--- libcmis.org/src/libcmis/oauth2-handler.cxx 2021-07-27 19:09:42.582249917 +0200
++++ libcmis/src/libcmis/oauth2-handler.cxx 2021-07-27 19:10:02.369249198 +0200
+@@ -158,6 +158,11 @@
+ return m_refresh;
+ }
+
++void OAuth2Handler::setRefreshToken( string refreshToken )
++{
++ m_refresh = refreshToken;
++}
++
+ string OAuth2Handler::getHttpHeader( )
+ {
+ string header;
+diff -ur libcmis.org/src/libcmis/oauth2-handler.hxx libcmis/src/libcmis/oauth2-handler.hxx
+--- libcmis.org/src/libcmis/oauth2-handler.hxx 2021-07-27 19:09:42.582249917 +0200
++++ libcmis/src/libcmis/oauth2-handler.hxx 2021-07-27 19:10:02.370249198 +0200
+@@ -61,6 +61,7 @@
+
+ std::string getAccessToken( ) ;
+ std::string getRefreshToken( ) ;
++ void setRefreshToken( std::string refreshToken ) ;
+
+ // adding HTTP auth header
+ std::string getHttpHeader( ) ;
+diff -ur libcmis.org/src/libcmis/onedrive-session.cxx libcmis/src/libcmis/onedrive-session.cxx
+--- libcmis.org/src/libcmis/onedrive-session.cxx 2021-07-27 19:09:42.583249917 +0200
++++ libcmis/src/libcmis/onedrive-session.cxx 2021-07-27 19:10:02.370249198 +0200
+@@ -68,6 +68,45 @@
+ {
+ }
+
++void OneDriveSession::setOAuth2Data( libcmis::OAuth2DataPtr oauth2 )
++{
++ m_oauth2Handler = new OAuth2Handler( this, oauth2 );
++ m_oauth2Handler->setOAuth2Parser( OAuth2Providers::getOAuth2Parser( getBindingUrl( ) ) );
++
++ oauth2Authenticate( );
++}
++
++void OneDriveSession::oauth2Authenticate()
++{
++ // treat the supplied password as refresh token
++ if (!m_password.empty())
++ {
++ try
++ {
++ m_inOAuth2Authentication = true;
++
++ m_oauth2Handler->setRefreshToken(m_password);
++ // Try to get new access tokens using the stored refreshtoken
++ m_oauth2Handler->refresh();
++ m_inOAuth2Authentication = false;
++ }
++ catch (const CurlException &e)
++ {
++ m_inOAuth2Authentication = false;
++ // refresh token expired or invalid, trigger initial auth (that in turn will hit the fallback with copy'n'paste method)
++ BaseSession::oauth2Authenticate();
++ }
++ }
++ else
++ {
++ BaseSession::oauth2Authenticate();
++ }
++}
++
++string OneDriveSession::getRefreshToken() {
++ return HttpSession::getRefreshToken();
++}
++
+ libcmis::RepositoryPtr OneDriveSession::getRepository( )
+ {
+ // Return a dummy repository since OneDrive doesn't have that notion
+diff -ur libcmis.org/src/libcmis/onedrive-session.hxx libcmis/src/libcmis/onedrive-session.hxx
+--- libcmis.org/src/libcmis/onedrive-session.hxx 2021-07-27 19:09:42.583249917 +0200
++++ libcmis/src/libcmis/onedrive-session.hxx 2021-07-27 19:10:02.370249198 +0200
+@@ -62,8 +62,14 @@
+
+ bool isAPathMatch( Json objectJson, std::string path );
+
++ virtual std::string getRefreshToken();
++
+ private:
+ OneDriveSession( );
++
++ virtual void setOAuth2Data( libcmis::OAuth2DataPtr oauth2 );
++
++ void oauth2Authenticate( );
+ };
+
+ #endif /* _ONEDRIVE_SESSION_HXX_ */
diff --git a/officecfg/registry/data/org/openoffice/Office/Common.xcu b/officecfg/registry/data/org/openoffice/Office/Common.xcu
index 23df2f148519..592023465e7b 100644
--- a/officecfg/registry/data/org/openoffice/Office/Common.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/Common.xcu
@@ -433,7 +433,7 @@
</prop>
<prop oor:name="CmisServersUrls">
<value>
- <it>https://www.googleapis.com/drive/v2</it>
+ <it>https://www.googleapis.com/drive/v3</it>
<it>https://graph.microsoft.com/v1.0</it>
<it>https://api.alfresco.com/cmis/versions/1.0/atom/</it>
<it></it>
diff --git a/ucb/source/ucp/cmis/auth_provider.cxx b/ucb/source/ucp/cmis/auth_provider.cxx
index dd7b4f9f1e3c..c4407f47cc3f 100644
--- a/ucb/source/ucp/cmis/auth_provider.cxx
+++ b/ucb/source/ucp/cmis/auth_provider.cxx
@@ -11,7 +11,10 @@
#define STD_TO_OUSTR( str ) OUString( str.c_str(), str.length( ), RTL_TEXTENCODING_UTF8 )
#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/task/PasswordContainer.hpp>
+#include <com/sun/star/task/XPasswordContainer2.hpp>
+#include <comphelper/processfactory.hxx>
#include <ucbhelper/simpleauthenticationrequest.hxx>
#include <ucbhelper/authenticationfallback.hxx>
@@ -64,6 +67,91 @@ namespace cmis
return false;
}
+ string AuthProvider::getRefreshToken(string& rUsername)
+ {
+ string refreshToken;
+ const css::uno::Reference<css::ucb::XCommandEnvironment> xEnv = getXEnv();
+ if (xEnv.is())
+ {
+ uno::Reference<task::XInteractionHandler> xIH = xEnv->getInteractionHandler();
+
+ if (rUsername.empty())
+ {
+ rtl::Reference<ucbhelper::SimpleAuthenticationRequest> xRequest
+ = new ucbhelper::SimpleAuthenticationRequest(
+ m_sUrl, m_sBindingUrl,
+ ucbhelper::SimpleAuthenticationRequest::EntityType::ENTITY_NA, OUString(),
+ ucbhelper::SimpleAuthenticationRequest::EntityType::ENTITY_MODIFY,
+ STD_TO_OUSTR(rUsername),
+ ucbhelper::SimpleAuthenticationRequest::EntityType::ENTITY_NA, OUString());
+ xIH->handle(xRequest.get());
+
+ rtl::Reference<ucbhelper::InteractionContinuation> xSelection
+ = xRequest->getSelection();
+
+ if (xSelection.is())
+ {
+ // Handler handled the request.
+ uno::Reference<task::XInteractionAbort> xAbort(xSelection.get(),
+ uno::UNO_QUERY);
+ if (!xAbort.is())
+ {
+ const rtl::Reference<ucbhelper::InteractionSupplyAuthentication>& xSupp
+ = xRequest->getAuthenticationSupplier();
+
+ rUsername = OUSTR_TO_STDSTR(xSupp->getUserName());
+ }
+ }
+ }
+
+ uno::Reference<uno::XComponentContext> xContext
+ = ::comphelper::getProcessComponentContext();
+ uno::Reference<task::XPasswordContainer2> xMasterPasswd
+ = task::PasswordContainer::create(xContext);
+ if (xMasterPasswd->hasMasterPassword())
+ {
+ xMasterPasswd->authorizateWithMasterPassword(xIH);
+ }
+ if (xMasterPasswd->isPersistentStoringAllowed())
+ {
+ task::UrlRecord aRec
+ = xMasterPasswd->findForName(m_sBindingUrl, STD_TO_OUSTR(rUsername), xIH);
+ if (aRec.UserList.hasElements() && aRec.UserList[0].Passwords.hasElements())
+ refreshToken = OUSTR_TO_STDSTR(aRec.UserList[0].Passwords[0]);
+ }
+ }
+ return refreshToken;
+ }
+
+ bool AuthProvider::storeRefreshToken(const string& username, const string& password,
+ const string& refreshToken)
+ {
+ if (refreshToken.empty())
+ return false;
+ if (password == refreshToken)
+ return true;
+ const css::uno::Reference<css::ucb::XCommandEnvironment> xEnv = getXEnv();
+ if (xEnv.is())
+ {
+ uno::Reference<task::XInteractionHandler> xIH = xEnv->getInteractionHandler();
+ uno::Reference<uno::XComponentContext> xContext
+ = ::comphelper::getProcessComponentContext();
+ uno::Reference<task::XPasswordContainer2> xMasterPasswd
+ = task::PasswordContainer::create(xContext);
+ uno::Sequence<OUString> aPasswd{ STD_TO_OUSTR(refreshToken) };
+ if (xMasterPasswd->isPersistentStoringAllowed())
+ {
+ if (xMasterPasswd->hasMasterPassword())
+ {
+ xMasterPasswd->authorizateWithMasterPassword(xIH);
+ }
+ xMasterPasswd->addPersistent(m_sBindingUrl, STD_TO_OUSTR(username), aPasswd, xIH);
+ return true;
+ }
+ }
+ return false;
+ }
+
css::uno::WeakReference< css::ucb::XCommandEnvironment> AuthProvider::sm_xEnv;
void AuthProvider::setXEnv(const css::uno::Reference< css::ucb::XCommandEnvironment>& xEnv )
@@ -76,7 +164,7 @@ namespace cmis
return sm_xEnv;
}
- char* AuthProvider::onedriveAuthCodeFallback( const char* url,
+ char* AuthProvider::copyWebAuthCodeFallback( const char* url,
const char* /*username*/,
const char* /*password*/ )
{
@@ -120,46 +208,6 @@ namespace cmis
return strdup( "" );
}
-
- char* AuthProvider::gdriveAuthCodeFallback( const char* /*url*/,
- const char* /*username*/,
- const char* /*password*/ )
- {
- const css::uno::Reference<
- css::ucb::XCommandEnvironment> xEnv = getXEnv( );
-
- if ( xEnv.is() )
- {
- uno::Reference< task::XInteractionHandler > xIH
- = xEnv->getInteractionHandler();
-
- if ( xIH.is() )
- {
- rtl::Reference< ucbhelper::AuthenticationFallbackRequest > xRequest
- = new ucbhelper::AuthenticationFallbackRequest (
- "PIN:", "" );
-
- xIH->handle( xRequest.get() );
-
- rtl::Reference< ucbhelper::InteractionContinuation > xSelection
- = xRequest->getSelection();
-
- if ( xSelection.is() )
- {
- // Handler handled the request.
- const rtl::Reference< ucbhelper::InteractionAuthFallback >&
- xAuthFallback = xRequest->getAuthFallbackInter( );
- if ( xAuthFallback.is() )
- {
- OUString code = xAuthFallback->getCode( );
- return strdup( OUSTR_TO_STDSTR( code ).c_str( ) );
- }
- }
- }
- }
-
- return strdup( "" );
- }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ucb/source/ucp/cmis/auth_provider.hxx b/ucb/source/ucp/cmis/auth_provider.hxx
index 24430401d278..462f7edba54d 100644
--- a/ucb/source/ucp/cmis/auth_provider.hxx
+++ b/ucb/source/ucp/cmis/auth_provider.hxx
@@ -39,11 +39,11 @@ namespace cmis
bool authenticationQuery( std::string& username, std::string& password ) override;
- static char* onedriveAuthCodeFallback( const char* url,
- const char* /*username*/,
- const char* /*password*/ );
+ std::string getRefreshToken( std::string& username );
+ bool storeRefreshToken(const std::string& username, const std::string& password,
+ const std::string& refreshToken);
- static char* gdriveAuthCodeFallback( const char* /*url*/,
+ static char* copyWebAuthCodeFallback( const char* url,
const char* /*username*/,
const char* /*password*/ );
diff --git a/ucb/source/ucp/cmis/cmis_content.cxx b/ucb/source/ucp/cmis/cmis_content.cxx
index 355575d185d1..edb13ddf2457 100644
--- a/ucb/source/ucp/cmis/cmis_content.cxx
+++ b/ucb/source/ucp/cmis/cmis_content.cxx
@@ -347,12 +347,15 @@ namespace cmis
string rPassword = OUSTR_TO_STDSTR( m_aURL.getPassword( ) );
bool bSkipInitialPWAuth = false;
- if ( m_aURL.getBindingUrl( ) == ONEDRIVE_BASE_URL ) {
+ if (m_aURL.getBindingUrl() == ONEDRIVE_BASE_URL
+ || m_aURL.getBindingUrl() == GDRIVE_BASE_URL)
+ {
// skip the initial username and pw-auth prompt, the only supported method is the
// auth-code-fallback one (login with your browser, copy code into the dialog)
// TODO: if LO were to listen on localhost for the request, it would be much nicer
// user experience
bSkipInitialPWAuth = true;
+ rPassword = aAuthProvider.getRefreshToken(rUsername);
}
bool bIsDone = false;
@@ -365,7 +368,9 @@ namespace cmis
libcmis::OAuth2DataPtr oauth2Data;
if ( m_aURL.getBindingUrl( ) == GDRIVE_BASE_URL )
{
- libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::gdriveAuthCodeFallback);
+ // reset the skip, so user gets a chance to cancel
+ bSkipInitialPWAuth = false;
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback);
oauth2Data.reset( new libcmis::OAuth2Data(
GDRIVE_AUTH_URL, GDRIVE_TOKEN_URL,
GDRIVE_SCOPE, GDRIVE_REDIRECT_URI,
@@ -380,7 +385,7 @@ namespace cmis
{
// reset the skip, so user gets a chance to cancel
bSkipInitialPWAuth = false;
- libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::onedriveAuthCodeFallback);
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider(AuthProvider::copyWebAuthCodeFallback);
oauth2Data.reset( new libcmis::OAuth2Data(
ONEDRIVE_AUTH_URL, ONEDRIVE_TOKEN_URL,
ONEDRIVE_SCOPE, ONEDRIVE_REDIRECT_URI,
@@ -412,6 +417,12 @@ namespace cmis
else
{
m_pProvider->registerSession(sSessionId, m_aURL.getUsername( ), m_pSession);
+ if (m_aURL.getBindingUrl() == ONEDRIVE_BASE_URL
+ || m_aURL.getBindingUrl() == GDRIVE_BASE_URL)
+ {
+ aAuthProvider.storeRefreshToken(rUsername, rPassword,
+ m_pSession->getRefreshToken());
+ }
}
bIsDone = true;
@@ -419,7 +430,10 @@ namespace cmis
catch( const libcmis::Exception & e )
{
if ( e.getType() != "permissionDenied" )
+ {
+ SAL_INFO("ucb.ucp.cmis", "Unexpected libcmis exception: " << e.what());
throw;
+ }
}
}
else
@@ -511,6 +525,7 @@ namespace cmis
}
catch ( const libcmis::Exception& )
{
+ SAL_INFO( "ucb.ucp.cmis", "object: " << OUSTR_TO_STDSTR(m_sObjectId));
throw libcmis::Exception( "Object not found" );
}
}
diff --git a/ucb/source/ucp/cmis/cmis_repo_content.cxx b/ucb/source/ucp/cmis/cmis_repo_content.cxx
index d98da53d5e2d..1bec3152b3b6 100644
--- a/ucb/source/ucp/cmis/cmis_repo_content.cxx
+++ b/ucb/source/ucp/cmis/cmis_repo_content.cxx
@@ -165,7 +165,7 @@ namespace cmis
libcmis::OAuth2DataPtr oauth2Data;
if ( m_aURL.getBindingUrl( ) == GDRIVE_BASE_URL )
{
- libcmis::SessionFactory::setOAuth2AuthCodeProvider( AuthProvider::gdriveAuthCodeFallback );
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider( AuthProvider::copyWebAuthCodeFallback );
oauth2Data.reset( new libcmis::OAuth2Data(
GDRIVE_AUTH_URL, GDRIVE_TOKEN_URL,
GDRIVE_SCOPE, GDRIVE_REDIRECT_URI,
@@ -178,7 +178,7 @@ namespace cmis
ALFRESCO_CLOUD_CLIENT_ID, ALFRESCO_CLOUD_CLIENT_SECRET ) );
if ( m_aURL.getBindingUrl( ) == ONEDRIVE_BASE_URL )
{
- libcmis::SessionFactory::setOAuth2AuthCodeProvider( AuthProvider::onedriveAuthCodeFallback );
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider( AuthProvider::copyWebAuthCodeFallback );
oauth2Data.reset( new libcmis::OAuth2Data(
ONEDRIVE_AUTH_URL, ONEDRIVE_TOKEN_URL,
ONEDRIVE_SCOPE, ONEDRIVE_REDIRECT_URI,
commit e8b1d3d43638eab00c921cd232c14c5ea1de6610
Author: Regina Henschel <rb.henschel at t-online.de>
AuthorDate: Fri Jul 30 23:18:39 2021 +0200
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
tdf#143619 validation circle anchor is special
For usual drawing objects, maStart in its Calc user data means the
cell address of left/top of snapRect/logicRect. For validation circle
it means 'address of cell to be validated'. Thus corrections might be
needed, if a general method is used for validation circle.
Here the method SetLogicRect() calls via broadcast
ScDrawLayer::SetCellAnchoredFromPosition(), which calculates maStart
from snapRect/logicRect. Because the circle is extended to cover a
larger area than the to be validated cell, maStart got the cell address
of the cell one left and one above of the to be validated cell.
Now the old, correct address is backuped and restored.
Change-Id: I9646da3f22fef45a6e47e59ef55a70307e2f9cc6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119715
Tested-by: Jenkins
Reviewed-by: Regina Henschel <rb.henschel at t-online.de>
(cherry picked from commit 0cff1aa48453ee0c05bafcac5360329fb6bf9557)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120147
Reviewed-by: Xisco Fauli <xiscofauli at libreoffice.org>
Signed-off-by: Xisco Fauli <xiscofauli at libreoffice.org>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120224
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice at googlemail.com>
diff --git a/sc/qa/unit/data/ods/tdf143619_validationCirclePos.ods b/sc/qa/unit/data/ods/tdf143619_validationCirclePos.ods
new file mode 100644
index 000000000000..6470d6a1f430
Binary files /dev/null and b/sc/qa/unit/data/ods/tdf143619_validationCirclePos.ods differ
diff --git a/sc/qa/unit/scshapetest.cxx b/sc/qa/unit/scshapetest.cxx
index 11b7875c83ee..ff156cc65df3 100644
--- a/sc/qa/unit/scshapetest.cxx
+++ b/sc/qa/unit/scshapetest.cxx
@@ -41,6 +41,7 @@ public:
ScShapeTest();
void saveAndReload(css::uno::Reference<css::lang::XComponent>& xComponent,
const OUString& rFilter);
+ void testTdf143619_validation_circle_pos();
void testTdf137082_LTR_to_RTL();
void testTdf137082_RTL_cell_anchored();
void testTdf137081_RTL_page_anchored();
@@ -64,6 +65,7 @@ public:
void testCustomShapeCellAnchoredRotatedShape();
CPPUNIT_TEST_SUITE(ScShapeTest);
+ CPPUNIT_TEST(testTdf143619_validation_circle_pos);
CPPUNIT_TEST(testTdf137082_LTR_to_RTL);
CPPUNIT_TEST(testTdf137082_RTL_cell_anchored);
CPPUNIT_TEST(testTdf137081_RTL_page_anchored);
@@ -189,6 +191,38 @@ static SdrObject* lcl_getSdrObjectWithAssert(ScDocument& rDoc, sal_uInt16 nObjNu
return pObj;
}
+void ScShapeTest::testTdf143619_validation_circle_pos()
+{
+ // Load a document, which has validation circle around cell E6.
+
+ OUString aFileURL;
+ createFileURL(u"tdf143619_validationCirclePos.ods", aFileURL);
+ uno::Reference<css::lang::XComponent> xComponent = loadFromDesktop(aFileURL);
+
+ // Get document
+ ScDocShell* pDocSh = lcl_getScDocShellWithAssert(xComponent);
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ // Get shape. That is the validation circle.
+ SdrObject* pObj = lcl_getSdrObjectWithAssert(rDoc, 0);
+
+ // Error was, that deleting row and col before E6 does not move circle to D5, but to B3.
+ // Delete first row and first column.
+ uno::Sequence<beans::PropertyValue> aPropertyValues = {
+ comphelper::makePropertyValue("ToPoint", OUString("$A$1")),
+ };
+ dispatchCommand(xComponent, ".uno:GoToCell", aPropertyValues);
+ dispatchCommand(xComponent, ".uno:DeleteRows", {});
+ dispatchCommand(xComponent, ".uno:GoToCell", aPropertyValues);
+ dispatchCommand(xComponent, ".uno:DeleteColumns", {});
+
+ // Without fix in place the position was (2007, 833)
+ Point aPos = pObj->GetSnapRect().TopLeft();
+ lcl_AssertPointEqualWithTolerance("after row and col delete", Point(6523, 1736), aPos, 1);
+
+ pDocSh->DoClose();
+}
+
void ScShapeTest::testTdf137082_LTR_to_RTL()
{
// Before the fix for tdf137081 and tdf137082, when flipping sheet from LTR to RTL, page anchored
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index 497ad478b146..15440fa3f94b 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -1061,6 +1061,7 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
// Validation circle for detective.
rData.setShapeRect(GetDocument(), pObj->GetLogicRect());
+ // rData.maStart should contain the address of the be validated cell.
tools::Rectangle aRect = GetCellRect(*GetDocument(), rData.maStart, true);
aRect.AdjustLeft( -250 );
aRect.AdjustRight(250 );
@@ -1074,7 +1075,13 @@ void ScDrawLayer::RecalcPos( SdrObject* pObj, ScDrawObjData& rData, bool bNegati
if (bRecording)
AddCalcUndo( std::make_unique<SdrUndoGeoObj>( *pObj ) );
rData.setShapeRect(GetDocument(), lcl_makeSafeRectangle(aRect));
+ // maStart has the meaning of "to be validated cell" in a validation circle. For usual
+ // drawing objects it has the meaning "left/top of logic/snap rect". Because the rectangle
+ // is expanded above, SetLogicRect() will set maStart to one cell left and one cell above
+ // of the to be validated cell. We need to backup the old value and restore it.
+ ScAddress aBackup(rData.maStart);
pObj->SetLogicRect(rData.getShapeRect());
+ rData.maStart = aBackup;
}
}
else if (rData.meType == ScDrawObjData::DetectiveArrow)
commit 71999c5a47ef972ea68306585e74f0e9031df03b
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Mon Aug 16 15:58:11 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
Resolves: tdf#143785 save/restore SdrModel::IsChanged
Change-Id: I253915c359cf72f80b21e21ff34e0ee406e5b3a8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120550
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
(cherry picked from commit 6dc23567639bebf18ceb8d9a3721228bffe14202)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120578
Reviewed-by: Michael Stahl <michael.stahl at allotropia.de>
diff --git a/cui/source/tabpages/transfrm.cxx b/cui/source/tabpages/transfrm.cxx
index cec57ecbbbe7..c8d0133ab58d 100644
--- a/cui/source/tabpages/transfrm.cxx
+++ b/cui/source/tabpages/transfrm.cxx
@@ -647,6 +647,7 @@ void SvxSlantTabPage::Reset(const SfxItemSet* rAttrs)
*pView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj()));
//save geometry
+ const bool bOrigModelChangeState = pView->GetModel()->IsChanged();
SdrCustomShapeGeometryItem aInitialGeometry(rSdrObjCustomShape.GetMergedItem(SDRATTR_CUSTOMSHAPE_GEOMETRY));
EnhancedCustomShape2d aShape(rSdrObjCustomShape);
@@ -690,6 +691,7 @@ void SvxSlantTabPage::Reset(const SfxItemSet* rAttrs)
//restore geometry
rSdrObjCustomShape.SetMergedItem(aInitialGeometry);
+ pView->GetModel()->SetChanged(bOrigModelChangeState);
}
for (int i = 0; i < 2; ++i)
commit 18d48230067ee0e4a4b819c941950657ef706d4c
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Tue Aug 17 15:43:00 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
Resolves: tdf#139220 with ~1000 selected shapes a11y UpdateSelection crawls
so fetch the selected shapes once and sort them for quick lookup in the
loop over maVisibleChildren.
As an side, not changed here, SvxShapeCollection::getByIndex looks
suboptimal with a body of
std::vector<Reference<uno::XInterface>> aElements(maShapeContainer.getElements());
return uno::makeAny(Reference<drawing::XShape>(aElements[Index].get()));
Change-Id: Idec7c003e7c5ee02000d4642d4fdb0d940548d97
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120584
Tested-by: Jenkins
Reviewed-by: Michael Stahl <michael.stahl at allotropia.de>
diff --git a/svx/source/accessibility/ChildrenManagerImpl.cxx b/svx/source/accessibility/ChildrenManagerImpl.cxx
index 893bc350f1f1..507063e09c43 100644
--- a/svx/source/accessibility/ChildrenManagerImpl.cxx
+++ b/svx/source/accessibility/ChildrenManagerImpl.cxx
@@ -38,6 +38,7 @@
#include <com/sun/star/container/XChild.hpp>
#include <comphelper/types.hxx>
#include <o3tl/safeint.hxx>
+#include <o3tl/sorted_vector.hxx>
#include <rtl/ustring.hxx>
#include <tools/debug.hxx>
#include <svx/SvxShapeTypes.hxx>
@@ -793,20 +794,6 @@ uno::Reference<XAccessible>
*/
void ChildrenManagerImpl::UpdateSelection()
{
- Reference<frame::XController> xController(maShapeTreeInfo.GetController());
- Reference<view::XSelectionSupplier> xSelectionSupplier (
- xController, uno::UNO_QUERY);
-
- // Try to cast the selection both to a multi selection and to a single
- // selection.
- Reference<container::XIndexAccess> xSelectedShapeAccess;
- Reference<drawing::XShape> xSelectedShape;
- if (xSelectionSupplier.is())
- {
- xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
- xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
- }
-
// Remember the current and new focused shape.
AccessibleShape* pCurrentlyFocusedShape = nullptr;
AccessibleShape* pNewFocusedShape = nullptr;
@@ -815,73 +802,101 @@ void ChildrenManagerImpl::UpdateSelection()
VEC_SHAPE vecSelect;
int nAddSelect=0;
bool bHasSelectedShape=false;
- for (const auto& rChild : maVisibleChildren)
+ if (!maVisibleChildren.empty())
{
- AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
- if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=nullptr)
+ Reference<frame::XController> xController(maShapeTreeInfo.GetController());
+ Reference<view::XSelectionSupplier> xSelectionSupplier (
+ xController, uno::UNO_QUERY);
+
+ // Try to cast the selection both to a multi selection and to a single
+ // selection.
+ Reference<container::XIndexAccess> xSelectedShapeAccess;
+ Reference<drawing::XShape> xSelectedShape;
+ if (xSelectionSupplier.is())
{
- short nRole = pAccessibleShape->getAccessibleRole();
- bool bDrawShape = (
- nRole == AccessibleRole::GRAPHIC ||
- nRole == AccessibleRole::EMBEDDED_OBJECT ||
- nRole == AccessibleRole::SHAPE ||
- nRole == AccessibleRole::IMAGE_MAP ||
- nRole == AccessibleRole::TABLE_CELL ||
- nRole == AccessibleRole::TABLE );
- bool bShapeIsSelected = false;
-
- // Look up the shape in the (single or multi-) selection.
- if (xSelectedShape.is())
+ xSelectedShapeAccess.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
+ xSelectedShape.set( xSelectionSupplier->getSelection(), uno::UNO_QUERY);
+ }
+
+ // tdf#139220 to quickly find if a given drawing::XShape is selected
+ o3tl::sorted_vector<css::uno::Reference<css::drawing::XShape>> aSortedSelectedShapes;
+ if (!xSelectedShape.is() && xSelectedShapeAccess.is())
+ {
+ sal_Int32 nCount = xSelectedShapeAccess->getCount();
+ aSortedSelectedShapes.reserve(nCount);
+ for (sal_Int32 i = 0; i < nCount; ++i)
{
- if (rChild.mxShape == xSelectedShape)
- {
- bShapeIsSelected = true;
- pNewFocusedShape = pAccessibleShape;
- }
+ css::uno::Reference<css::drawing::XShape> xShape(xSelectedShapeAccess->getByIndex(i), uno::UNO_QUERY);
+ aSortedSelectedShapes.insert(xShape);
}
- else if (xSelectedShapeAccess.is())
+ }
+
+ for (const auto& rChild : maVisibleChildren)
+ {
+ AccessibleShape* pAccessibleShape = rChild.GetAccessibleShape();
+ if (rChild.mxAccessibleShape.is() && rChild.mxShape.is() && pAccessibleShape!=nullptr)
{
- sal_Int32 nCount=xSelectedShapeAccess->getCount();
- for (sal_Int32 i=0; i<nCount&&!bShapeIsSelected; i++)
- if (xSelectedShapeAccess->getByIndex(i) == rChild.mxShape)
+ short nRole = pAccessibleShape->getAccessibleRole();
+ bool bDrawShape = (
+ nRole == AccessibleRole::GRAPHIC ||
+ nRole == AccessibleRole::EMBEDDED_OBJECT ||
+ nRole == AccessibleRole::SHAPE ||
+ nRole == AccessibleRole::IMAGE_MAP ||
+ nRole == AccessibleRole::TABLE_CELL ||
+ nRole == AccessibleRole::TABLE );
+ bool bShapeIsSelected = false;
+
+ // Look up the shape in the (single or multi-) selection.
+ if (xSelectedShape.is())
+ {
+ if (rChild.mxShape == xSelectedShape)
+ {
+ bShapeIsSelected = true;
+ pNewFocusedShape = pAccessibleShape;
+ }
+ }
+ else if (!aSortedSelectedShapes.empty())
+ {
+ if (aSortedSelectedShapes.find(rChild.mxShape) != aSortedSelectedShapes.end())
{
bShapeIsSelected = true;
// In a multi-selection no shape has the focus.
- if (nCount == 1)
+ if (aSortedSelectedShapes.size() == 1)
pNewFocusedShape = pAccessibleShape;
}
- }
+ }
- // Set or reset the SELECTED state.
- if (bShapeIsSelected)
- {
- if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
+ // Set or reset the SELECTED state.
+ if (bShapeIsSelected)
{
- if (bDrawShape)
+ if (pAccessibleShape->SetState (AccessibleStateType::SELECTED))
{
- vecSelect.emplace_back(pAccessibleShape,true);
- ++nAddSelect;
+ if (bDrawShape)
+ {
+ vecSelect.emplace_back(pAccessibleShape,true);
+ ++nAddSelect;
+ }
+ }
+ else
+ {//Selected not change,has selected shape before
+ bHasSelectedShape=true;
}
}
else
- {//Selected not change,has selected shape before
- bHasSelectedShape=true;
- }
- }
- else
- //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
- {
- if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
+ //pAccessibleShape->ResetState (AccessibleStateType::SELECTED);
{
- if(bDrawShape)
+ if(pAccessibleShape->ResetState (AccessibleStateType::SELECTED))
{
- vecSelect.emplace_back(pAccessibleShape,false);
+ if(bDrawShape)
+ {
+ vecSelect.emplace_back(pAccessibleShape,false);
+ }
}
}
+ // Does the shape have the current selection?
+ if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
+ pCurrentlyFocusedShape = pAccessibleShape;
}
- // Does the shape have the current selection?
- if (pAccessibleShape->GetState (AccessibleStateType::FOCUSED))
- pCurrentlyFocusedShape = pAccessibleShape;
}
}
commit 2ac9132cb5b69ac8886bd7dd1086da225ee10cd8
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Tue Aug 17 09:15:13 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
Resolves: tdf#142003 tracked changes in footnotes offset in .doc import
Reverts:
commit e71d05eaa9a8c9e628b256f3e889b85ac11ed474
Author: Caolán McNamara <caolanm at redhat.com>
Date: Fri Apr 27 15:42:26 2018 +0100
ofz#8038 defer subdocument redlining to end of parse like main document
Change-Id: Ie8d7a98c7927dcba53228ebcd991d715d8faabe7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120563
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
(cherry picked from commit b5870d727685ec10447e8ae446ada895250fec2e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120581
Reviewed-by: Xisco Fauli <xiscofauli at libreoffice.org>
diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx
index b637c797225f..42e8c415b156 100644
--- a/sw/source/filter/ww8/ww8par.cxx
+++ b/sw/source/filter/ww8/ww8par.cxx
@@ -2095,7 +2095,6 @@ void WW8ReaderSave::Restore( SwWW8ImplReader* pRdr )
pRdr->m_xCtrlStck = std::move(mxOldStck);
pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
- pRdr->m_aFrameRedlines.emplace(std::move(pRdr->m_xRedlineStack));
pRdr->m_xRedlineStack = std::move(mxOldRedlines);
pRdr->DeleteAnchorStack();
@@ -5386,8 +5385,6 @@ ErrCode SwWW8ImplReader::CoreLoad(WW8Glossary const *pGloss)
// are updated
m_aExtraneousParas.delete_all_from_doc();
m_xRedlineStack->closeall(*m_pPaM->GetPoint());
- while (!m_aFrameRedlines.empty())
- m_aFrameRedlines.pop();
// For i120928,achieve the graphics from the special bookmark with is for graphic bullet
{
diff --git a/sw/source/filter/ww8/ww8par.hxx b/sw/source/filter/ww8/ww8par.hxx
index 4148344a9981..d309b756d5e2 100644
--- a/sw/source/filter/ww8/ww8par.hxx
+++ b/sw/source/filter/ww8/ww8par.hxx
@@ -1106,8 +1106,7 @@ private:
This stack is for redlines, because their sequence of discovery can
be out of order of their order of insertion into the document.
*/
- std::stack<std::unique_ptr<sw::util::RedlineStack>> m_aFrameRedlines; //inside frames, tables, etc
- std::unique_ptr<sw::util::RedlineStack> m_xRedlineStack; //main document
+ std::unique_ptr<sw::util::RedlineStack> m_xRedlineStack;
/*
This stack is for fields that get referenced later, e.g. BookMarks and TOX.
diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx
index bf5a27528b6e..ad64bb616bd1 100644
--- a/sw/source/filter/ww8/ww8par2.cxx
+++ b/sw/source/filter/ww8/ww8par2.cxx
@@ -2750,7 +2750,6 @@ void WW8TabDesc::MoveOutsideTable()
void WW8TabDesc::FinishSwTable()
{
m_pIo->m_xRedlineStack->closeall(*m_pIo->m_pPaM->GetPoint());
- m_pIo->m_aFrameRedlines.emplace(std::move(m_pIo->m_xRedlineStack));
m_pIo->m_xRedlineStack = std::move(mxOldRedlineStack);
WW8DupProperties aDup(m_pIo->m_rDoc,m_pIo->m_xCtrlStck.get());
commit 6ae7561d25a1920ebc4ffb14dcfb1fc25c03b7e1
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Mon Aug 16 15:32:07 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
tdf#143778 these async callbacks expect to have SdrModel::IsChanged of false
when they are entered. They are adapted from the original non-async
SwDrawShell::ExecDrawDlg where the start of SwDrawShell::ExecDrawDlg has...
bool bChanged = pDoc->IsChanged();
pDoc->SetChanged(false);
and the end has
if (pDoc->IsChanged())
GetShell().SetModified();
else
if (bChanged)
pDoc->SetChanged();
and before async dialogs the start and end happened before and after the
dialog appeared and disappeared. The intent seems to be unset the
sdrmodel-changed and restore its original state if the dialogs caused
nothing to happen and to explicitly set SetModified on the document if
something did.
Now the async dialogs callback happens after SwDrawShell::ExecDrawDlg
has ended and so the callbacks start with SdrModel::IsChanged at its
original value (restored by the end of ExecDrawDlg), not the "false"
they were originally written to expect.
For simplicity set the SdrModel IsChanged to false at the start of the
callbacks and continue to restore to the passed in bChanged state
if there was no changes by the callback.
Change-Id: I671b35acab6d1b391fa7e6590c09f8be135449b0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120548
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
(cherry picked from commit c64f221fc2e22ffa60c4d78240893f7f04531b3e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120576
Reviewed-by: Adolfo Jayme Barrientos <fitojb at ubuntu.com>
diff --git a/sw/source/uibase/shells/drawdlg.cxx b/sw/source/uibase/shells/drawdlg.cxx
index 114b7f33b055..c80f4960f657 100644
--- a/sw/source/uibase/shells/drawdlg.cxx
+++ b/sw/source/uibase/shells/drawdlg.cxx
@@ -115,6 +115,8 @@ void SwDrawShell::ExecDrawDlg(SfxRequest& rReq)
pDlg->StartExecuteAsync([bChanged, bHasMarked, pDoc, pDlg, pSh, pView, this](
sal_Int32 nResult){
+ pDoc->SetChanged(false);
+
if (nResult == RET_OK)
{
pSh->StartAction();
@@ -168,6 +170,8 @@ void SwDrawShell::ExecDrawDlg(SfxRequest& rReq)
pDlg->StartExecuteAsync([bChanged, bHasMarked, pDoc, pDlg, pSh, pView, this](
sal_Int32 nResult){
+ pDoc->SetChanged(false);
+
if (nResult == RET_OK)
{
pSh->StartAction();
@@ -210,9 +214,8 @@ void SwDrawShell::ExecDrawDlg(SfxRequest& rReq)
if (pDoc->IsChanged())
GetShell().SetModified();
- else
- if (bChanged)
- pDoc->SetChanged();
+ else if (bChanged)
+ pDoc->SetChanged();
}
namespace
diff --git a/sw/source/uibase/shells/drwbassh.cxx b/sw/source/uibase/shells/drwbassh.cxx
index f901f32cc15d..274a60c52028 100644
--- a/sw/source/uibase/shells/drwbassh.cxx
+++ b/sw/source/uibase/shells/drwbassh.cxx
@@ -235,6 +235,8 @@ void SwDrawBaseShell::Execute(SfxRequest const &rReq)
pDlg->StartExecuteAsync([bCaption, bChanged, pDlg, pFrameFormat, pSdrView,
pSh, &rMarkList, this](
sal_Int32 nResult){
+ pSdrView->GetModel()->SetChanged(false);
+
if (nResult == RET_OK)
{
SwFormatVertOrient aVOrientFinal(pFrameFormat->GetFormatAttr(RES_VERT_ORIENT));
commit 093f3e41f632429ff1899432d533b128e04b4dc8
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Jul 16 17:26:23 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
tdf#143357 use a DateFormatter and a separate Calendar menubutton
similar to what we ended up with in DateControl in
svtools/source/brwbox/ebbcontrols.cxx
Change-Id: I37c843ff7e1e8e39b318db80fe590ce5f796f46a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120454
Tested-by: Jenkins
Reviewed-by: Adolfo Jayme Barrientos <fitojb at ubuntu.com>
diff --git a/extensions/source/propctrlr/propcontroller.cxx b/extensions/source/propctrlr/propcontroller.cxx
index 4f3365e6b099..0f0409d861e0 100644
--- a/extensions/source/propctrlr/propcontroller.cxx
+++ b/extensions/source/propctrlr/propcontroller.cxx
@@ -755,8 +755,8 @@ namespace pcr
case PropertyControlType::DateField:
{
std::unique_ptr<weld::Builder> xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/datefield.ui", m_xContext));
- auto pMenuButton = xBuilder->weld_menu_button("datefield");
- auto pControl = new ODateControl(std::make_unique<SvtCalendarBox>(std::move(pMenuButton)), std::move(xBuilder), bCreateReadOnly);
+ auto pContainer = xBuilder->weld_container("datefield");
+ auto pControl = new ODateControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly);
pControl->SetModifyHandler();
xControl = pControl;
break;
diff --git a/extensions/source/propctrlr/standardcontrol.cxx b/extensions/source/propctrlr/standardcontrol.cxx
index ef2645a635a1..76fb572fe386 100644
--- a/extensions/source/propctrlr/standardcontrol.cxx
+++ b/extensions/source/propctrlr/standardcontrol.cxx
@@ -90,34 +90,75 @@ namespace pcr
}
//= ODateControl
- ODateControl::ODateControl(std::unique_ptr<SvtCalendarBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
+ ODateControl::ODateControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly)
: ODateControl_Base(PropertyControlType::DateField, std::move(xBuilder), std::move(xWidget), bReadOnly)
+ , m_xEntry(m_xBuilder->weld_entry("entry"))
+ , m_xCalendarBox(std::make_unique<SvtCalendarBox>(m_xBuilder->weld_menu_button("button"), false))
{
+ m_xEntryFormatter.reset(new weld::DateFormatter(*m_xEntry));
+
+ m_xEntryFormatter->SetStrictFormat(true);
+ m_xEntryFormatter->SetMin(::Date(1, 1, 1600));
+ m_xEntryFormatter->SetMax(::Date(1, 1, 9999));
+
+ m_xEntryFormatter->SetExtDateFormat(ExtDateFieldFormat::SystemShortYYYY);
+ m_xEntryFormatter->EnableEmptyField(true);
+
+ m_xCalendarBox->connect_activated(LINK(this, ODateControl, ActivateHdl));
+
+ m_xCalendarBox->get_button().connect_toggled(LINK(this, ODateControl, ToggleHdl));
}
- void SAL_CALL ODateControl::setValue( const Any& _rValue )
+ void SAL_CALL ODateControl::disposing()
{
- SvtCalendarBox* pCalendarBox = getTypedControlWindow();
+ m_xEntryFormatter.reset();
+ m_xEntry.reset();
+ m_xCalendarBox.reset();
+ ODateControl_Base::disposing();
+ }
+ void SAL_CALL ODateControl::setValue( const Any& _rValue )
+ {
util::Date aUNODate;
if ( !( _rValue >>= aUNODate ) )
{
- pCalendarBox->set_date(::Date(::Date::SYSTEM));
- pCalendarBox->set_label("");
+ m_xEntry->set_text(OUString());
}
else
{
::Date aDate( aUNODate.Day, aUNODate.Month, aUNODate.Year );
- pCalendarBox->set_date(aDate);
+ m_xEntryFormatter->SetDate(aDate);
}
}
+ IMPL_LINK_NOARG(ODateControl, ActivateHdl, SvtCalendarBox&, void)
+ {
+ m_xEntryFormatter->SetDate(m_xCalendarBox->get_date());
+ setModified();
+ m_xEntry->grab_focus();
+ }
+
+ IMPL_LINK(ODateControl, ToggleHdl, weld::ToggleButton&, rToggle, void)
+ {
+ if (!rToggle.get_active())
+ return;
+ ::Date aDate = m_xEntryFormatter->GetDate();
+ if (aDate.IsEmpty())
+ {
+ // with an empty date preselect today in the calendar
+ aDate = ::Date(::Date::SYSTEM);
+ }
+ m_xCalendarBox->set_date(aDate);
+ }
+
Any SAL_CALL ODateControl::getValue()
{
Any aPropValue;
- ::Date aDate(getTypedControlWindow()->get_date());
- if (!aDate.IsEmpty())
+ if (!m_xEntry->get_text().isEmpty())
+ {
+ ::Date aDate(m_xEntryFormatter->GetDate());
aPropValue <<= aDate.GetUNODate();
+ }
return aPropValue;
}
diff --git a/extensions/source/propctrlr/standardcontrol.hxx b/extensions/source/propctrlr/standardcontrol.hxx
index 0ed0fc635093..9c41b4362807 100644
--- a/extensions/source/propctrlr/standardcontrol.hxx
+++ b/extensions/source/propctrlr/standardcontrol.hxx
@@ -61,11 +61,18 @@ namespace pcr
};
//= ODateControl
- typedef CommonBehaviourControl<css::inspection::XPropertyControl, SvtCalendarBox> ODateControl_Base;
+ typedef CommonBehaviourControl<css::inspection::XPropertyControl, weld::Container> ODateControl_Base;
class ODateControl : public ODateControl_Base
{
+ std::unique_ptr<weld::Entry> m_xEntry;
+ std::unique_ptr<SvtCalendarBox> m_xCalendarBox;
+ std::unique_ptr<weld::DateFormatter> m_xEntryFormatter;
+
+ DECL_LINK(ActivateHdl, SvtCalendarBox&, void);
+ DECL_LINK(ToggleHdl, weld::ToggleButton&, void);
+
public:
- ODateControl(std::unique_ptr<SvtCalendarBox> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
+ ODateControl(std::unique_ptr<weld::Container> xWidget, std::unique_ptr<weld::Builder> xBuilder, bool bReadOnly);
// XPropertyControl
virtual css::uno::Any SAL_CALL getValue() override;
@@ -75,10 +82,18 @@ namespace pcr
virtual void SetModifyHandler() override
{
ODateControl_Base::SetModifyHandler();
- getTypedControlWindow()->connect_selected( LINK( this, CommonBehaviourControlHelper, DateModifiedHdl ) );
+
+ m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xEntryFormatter->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+ m_xCalendarBox->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) );
+ m_xCalendarBox->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) );
+
+ m_xEntryFormatter->connect_changed(LINK(this, CommonBehaviourControlHelper, EditModifiedHdl));
}
- virtual weld::Widget* getWidget() override { return &getTypedControlWindow()->get_button(); }
+ virtual void SAL_CALL disposing() override;
+
+ virtual weld::Widget* getWidget() override { return getTypedControlWindow(); }
};
//= OEditControl
diff --git a/extensions/uiconfig/spropctrlr/ui/datefield.ui b/extensions/uiconfig/spropctrlr/ui/datefield.ui
index e064f618bfd5..7b6b6ab17f59 100644
--- a/extensions/uiconfig/spropctrlr/ui/datefield.ui
+++ b/extensions/uiconfig/spropctrlr/ui/datefield.ui
@@ -1,17 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.38.2 -->
<interface domain="pcr">
<requires lib="gtk+" version="3.20"/>
- <object class="GtkMenuButton" id="datefield">
+ <object class="GtkImage" id="image7">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="focus-on-click">True</property>
- <property name="receives_default">False</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">sc/res/date.png</property>
+ <property name="icon_size">2</property>
+ </object>
+ <object class="GtkBox" id="datefield">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
<property name="hexpand">True</property>
- <property name="draw_indicator">True</property>
- <property name="label" translatable="no"></property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="entry">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
<child>
- <placeholder/>
+ <object class="GtkMenuButton" id="button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="image">image7</property>
+ <property name="margin-start">1</property>
+ <property name="always_show_image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
</interface>
diff --git a/include/svtools/ctrlbox.hxx b/include/svtools/ctrlbox.hxx
index 43347a14ce40..9cea6647f461 100644
--- a/include/svtools/ctrlbox.hxx
+++ b/include/svtools/ctrlbox.hxx
@@ -289,7 +289,7 @@ private:
class SVT_DLLPUBLIC SvtCalendarBox
{
public:
- SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl);
+ SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl, bool bUseLabel = true);
~SvtCalendarBox();
weld::MenuButton& get_button() { return *m_xControl; }
@@ -315,6 +315,8 @@ private:
DECL_LINK(SelectHdl, weld::Calendar&, void);
DECL_LINK(ActivateHdl, weld::Calendar&, void);
+ bool m_bUseLabel;
+
std::unique_ptr<weld::MenuButton> m_xControl;
std::unique_ptr<weld::Builder> m_xBuilder;
std::unique_ptr<weld::Widget> m_xTopLevel;
diff --git a/solenv/sanitizers/ui/modules/spropctrlr.suppr b/solenv/sanitizers/ui/modules/spropctrlr.suppr
index 466a32974a5d..5a7ccb3e54a8 100644
--- a/solenv/sanitizers/ui/modules/spropctrlr.suppr
+++ b/solenv/sanitizers/ui/modules/spropctrlr.suppr
@@ -1,4 +1,6 @@
extensions/uiconfig/spropctrlr/ui/browserline.ui://GtkLabel[@id='label'] orphan-label
+extensions/uiconfig/spropctrlr/ui/datefield.ui://GtkEntry[@id='entry'] no-labelled-by
+extensions/uiconfig/spropctrlr/ui/datefield.ui://GtkMenuButton[@id='button'] button-no-label
extensions/uiconfig/spropctrlr/ui/datetimefield.ui://GtkSpinButton[@id='timefield'] no-labelled-by
extensions/uiconfig/spropctrlr/ui/formattedcontrol.ui://GtkSpinButton[@id='formattedcontrol'] no-labelled-by
extensions/uiconfig/spropctrlr/ui/formattedsample.ui://GtkEntry[@id='entry'] no-labelled-by
diff --git a/svtools/source/control/ctrlbox.cxx b/svtools/source/control/ctrlbox.cxx
index 7c7f61cb61f8..a70d6d6c4120 100644
--- a/svtools/source/control/ctrlbox.cxx
+++ b/svtools/source/control/ctrlbox.cxx
@@ -1643,8 +1643,9 @@ void SvtLineListBox::UpdatePreview()
}
}
-SvtCalendarBox::SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl)
- : m_xControl(std::move(pControl))
+SvtCalendarBox::SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl, bool bUseLabel)
+ : m_bUseLabel(bUseLabel)
+ , m_xControl(std::move(pControl))
, m_xBuilder(Application::CreateBuilder(m_xControl.get(), "svt/ui/datewindow.ui"))
, m_xTopLevel(m_xBuilder->weld_widget("date_popup_window"))
, m_xCalendar(m_xBuilder->weld_calendar("date"))
@@ -1662,6 +1663,8 @@ void SvtCalendarBox::set_date(const Date& rDate)
void SvtCalendarBox::set_label_from_date()
{
+ if (!m_bUseLabel)
+ return;
const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
m_xControl->set_label(rLocaleData.getDate(m_xCalendar->get_date()));
}
commit 718313f86f2f42d7340d5c10309027c02555912e
Author: Eike Rathke <erack at redhat.com>
AuthorDate: Mon Aug 16 21:46:44 2021 +0200
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
Resolves: tdf#96561 Include embedded null-characters while assembling CSV line
... instead of prematurely ending analysis and skipping the
remainder that is still part of data read.
Change-Id: I8f34bc9672e37f9c1c1ae81ddeba464360add7c2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120555
Reviewed-by: Eike Rathke <erack at redhat.com>
Tested-by: Jenkins
(cherry picked from commit 7bd03074ae7362d8fffe5182529626a0b43a0ed1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120572
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx
index 3f86cc86edb7..7233b14ad640 100644
--- a/sc/source/ui/docshell/impex.cxx
+++ b/sc/source/ui/docshell/impex.cxx
@@ -2476,8 +2476,17 @@ Label_RetryWithNewSep:
while (!rStream.eof() && aStr.getLength() < nArbitraryLineLengthLimit)
{
const sal_Unicode * p = aStr.getStr() + nLastOffset;
- while (*p)
+ const sal_Unicode * const pStop = aStr.getStr() + aStr.getLength();
+ while (p < pStop)
{
+ if (!*p)
+ {
+ // Skip embedded null-characters. They don't change
+ // anything and are handled at a higher level.
+ ++p;
+ continue;
+ }
+
if (nQuotes)
{
if (*p == cFieldQuote)
commit bf319ecbdfb62be62eba2ba8037e2c5c46e0ac5b
Author: Julien Nabet <serval2412 at yahoo.fr>
AuthorDate: Mon Aug 16 12:48:14 2021 +0200
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:52 2021 +0200
Related tdf#143895: Mysql MEDIUMINT is DataType::INTEGER not DataType::SMALLINT
Change-Id: I324b18cc164cb2f38b7b8411c557c6c208e8d69d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120536
Reviewed-by: Lionel Mamane <lionel at mamane.lu>
Tested-by: Jenkins
(cherry picked from commit 997ff7166ceca0a5af80297a0e789af2ff0c6617)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120448
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.cxx b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
index 7ed11fe3ff13..878efdc3be24 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
@@ -193,11 +193,11 @@ sal_Int32 mysqlStrToOOOType(const OUString& sType)
// TODO other types.
if (sType.equalsIgnoreAsciiCase("tiny") || sType.equalsIgnoreAsciiCase("tinyint"))
return css::sdbc::DataType::TINYINT;
- if (sType.equalsIgnoreAsciiCase("smallint") || sType.equalsIgnoreAsciiCase("mediumint"))
+ if (sType.equalsIgnoreAsciiCase("smallint"))
return css::sdbc::DataType::SMALLINT;
if (sType.equalsIgnoreAsciiCase("longtext"))
return css::sdbc::DataType::LONGVARCHAR;
- if (sType.equalsIgnoreAsciiCase("int"))
+ if (sType.equalsIgnoreAsciiCase("int") || sType.equalsIgnoreAsciiCase("mediumint"))
return css::sdbc::DataType::INTEGER;
if (sType.equalsIgnoreAsciiCase("varchar") || sType.equalsIgnoreAsciiCase("set")
|| sType.equalsIgnoreAsciiCase("enum"))
commit 021ab27b64c63dd947328da03131397eaf9af3bf
Author: Julien Nabet <serval2412 at yahoo.fr>
AuthorDate: Tue Jul 20 23:04:55 2021 +0200
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:51 2021 +0200
tdf#143452: make 2 buttons in the date form control translatable
Regression from:
https://cgit.freedesktop.org/libreoffice/core/commit/?id=bafd50ee06d982e19d54fae0f9d8f968a2dedbd4
weld DateField Calendar floating window
Change-Id: I43c108908c6e802f3a8014ccf3fa243bebcae0ac
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119293
Tested-by: Jenkins
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice at googlemail.com>
(cherry picked from commit 73503ce975ce0923bfe2cfd075ac8b91de20f29e)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120445
Reviewed-by: Adolfo Jayme Barrientos <fitojb at ubuntu.com>
diff --git a/svtools/uiconfig/ui/calendar.ui b/svtools/uiconfig/ui/calendar.ui
index 735506d418d7..1273369878c6 100644
--- a/svtools/uiconfig/ui/calendar.ui
+++ b/svtools/uiconfig/ui/calendar.ui
@@ -40,7 +40,7 @@
<property name="layout_style">spread</property>
<child>
<object class="GtkButton" id="today">
- <property name="label" context="calendar|STR_SVT_CALENDAR_TODAY">Today</property>
+ <property name="label" translatable="yes" context="calendar|STR_SVT_CALENDAR_TODAY">Today</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">True</property>
@@ -55,7 +55,7 @@
</child>
<child>
<object class="GtkButton" id="none">
- <property name="label" context="calendar|STR_SVT_CALENDAR_NONE">None</property>
+ <property name="label" translatable="yes" context="calendar|STR_SVT_CALENDAR_NONE">None</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="no_show_all">True</property>
commit 58addb876f6fb39c187daac2183003d30794ad95
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Jul 16 15:44:40 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:51 2021 +0200
Related: tdf#143357 explicitly set the default of focus-on-click
this should already be the default according to
https://developer.gnome.org/gtk3/stable/GtkWidget.html but it's
apparently False nevertheless, so make it explicit here for these
widgets where there is a focus watcher to commit their changes and the
absence of this is non-cosmetic. Just these initially for a small
backportable change.
Change-Id: I96442b4e844ce0446f56276c1b648ca5ce57b740
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119077
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
(cherry picked from commit a36447215fa13f3ca92b22ac63e8164859ddb8ef)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120428
Reviewed-by: Michael Stahl <michael.stahl at allotropia.de>
diff --git a/extensions/uiconfig/spropctrlr/ui/colorlistbox.ui b/extensions/uiconfig/spropctrlr/ui/colorlistbox.ui
index 7361e0d11947..40ae63eac62a 100644
--- a/extensions/uiconfig/spropctrlr/ui/colorlistbox.ui
+++ b/extensions/uiconfig/spropctrlr/ui/colorlistbox.ui
@@ -5,6 +5,7 @@
<object class="GtkMenuButton" id="colorlistbox">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="focus-on-click">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="draw_indicator">True</property>
diff --git a/extensions/uiconfig/spropctrlr/ui/datefield.ui b/extensions/uiconfig/spropctrlr/ui/datefield.ui
index 6ca77af072ee..e064f618bfd5 100644
--- a/extensions/uiconfig/spropctrlr/ui/datefield.ui
+++ b/extensions/uiconfig/spropctrlr/ui/datefield.ui
@@ -5,6 +5,7 @@
<object class="GtkMenuButton" id="datefield">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="focus-on-click">True</property>
<property name="receives_default">False</property>
<property name="hexpand">True</property>
<property name="draw_indicator">True</property>
diff --git a/extensions/uiconfig/spropctrlr/ui/datetimefield.ui b/extensions/uiconfig/spropctrlr/ui/datetimefield.ui
index aed958450b1e..f736a8e63221 100644
--- a/extensions/uiconfig/spropctrlr/ui/datetimefield.ui
+++ b/extensions/uiconfig/spropctrlr/ui/datetimefield.ui
@@ -16,6 +16,7 @@
<object class="GtkMenuButton" id="datefield">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="focus-on-click">True</property>
<property name="receives_default">False</property>
<property name="hexpand">True</property>
<property name="draw_indicator">True</property>
commit 3cc1ca4583404a9c5f304226d3a5c89a1101386f
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Jul 16 15:53:00 2021 +0100
Commit: Andras Timar <andras.timar at collabora.com>
CommitDate: Tue Aug 24 14:50:51 2021 +0200
Related: tdf#143357 set blank label for no date
instead of current system date
Change-Id: Ic504b34990a8ea5151ec653de2db860c1cd4b8ba
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list