How to use Share API in macOS and Qt Quick

From Qt Wiki
Jump to navigation Jump to search
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.


Hi everyone!

In this article I've tried to explain how to use macOS Share API in your Qt Quick app. Share API was implemented in OS X Yosemite (v10.10).

As you know all frameworks in macOS which you could use in your application created with Objective-C/C+. That's why you can't use framework in your C+ classes. You need to rename your .cpp file to .mm and then you can call Objective-C code. But sometimes you need to call methods with arguments with Objective-C. As you know in .h file you can't call Objective-C code. You must create Objective-C class which will call all needed methods to work with target framework.

Classes with Share API support.

First you need to create class with all methods in Objective-C/C++ to use Share API. To do this you need follow a few steps:

  1. Create a new class and rename .cpp file to .mm.
  2. Add .h file to .pro of your project in section "OBJECTIVE_HEADERS" and .mm to "OBJECTIVE_SOURCES".
  3. Change .h file content to this code:
#ifdef __cplusplus
extern "C" {
#endif

#import <Foundation/Foundation.h>
#import <Social/Social.h>

/**

typedef QfSharePickerItemClicked *

param sharingService Selected type of sharing.
 *

author Andrew Shapovelov*/

typedef void(QfSharePickerItemClicked)(NSSharingService* sharingService);


/**

class QfSharePicker
 *

brief Object to show share menu. *

author Andrew Shapovalov*/

interface QfSharePicker : NSObject /**

brief Create a new object.
 *

param view View on what will show share menu. *

param frame Rect to show share window.
 *

param datas Datas items to share. *

param block Block of code to select item.
 *

author Andrew Shapovalov*/

- (instancetype)initWithView:(NSView*)view frame:(NSRect)frame datasArray:(NSArray*)datas onItemClicked:(QfSharePickerItemClicked)block;

end

#ifdef __cplusplus
}
#endif
  1. Change .mm file content to this code:
#import "qfsharepicker.h"
#include <QtCore>

/**

brief The private methods and properties of QfSharePicker class. *

author Andrew Shapovalov*/

interface QfSharePicker () <NSSharingServicePickerDelegate, NSSharingServiceDelegate>

/** Sharing service picker.*/

property (nonatomic, retain) NSSharingServicePicker''' picker;

/** Block of code to select item.*/

property (nonatomic, copy) QfSharePickerItemClicked onItemClicked;

end

implementation QfSharePicker

  1. pragma mark - Init methods

- (instancetype)initWithView:(NSView)view frame:(NSRect)frame datasArray:(NSArray*)datas onItemClicked:(QfSharePickerItemClicked)block {

self = [super init];
if(self)
{
self.onItemClicked = block;
self.picker = [[NSSharingServicePicker alloc] initWithItems: datas];
self.picker.delegate = self;
[self.picker showRelativeToRect:frame ofView:view preferredEdge:NSMinXEdge];
}
return self;

}


  1. pragma mark - NSSharingServicePickerDelegate methods

- (void)sharingServicePicker:(NSSharingServicePicker )sharingServicePicker didChooseSharingService:(NSSharingService)service {

if(self.picker == sharingServicePicker)
{
if(self.onItemClicked)
{
self.onItemClicked(service);
}
}

}

- (id <NSSharingServiceDelegate>)sharingServicePicker:(NSSharingServicePicker )sharingServicePicker delegateForSharingService:(NSSharingService)sharingService {

Q_UNUSED(sharingService);
if(self.picker == sharingServicePicker)
{
}
return self;

}

  1. pragma mark - NSSharingServiceDelegate methods

- (void)sharingService:(NSSharingService )sharingService willShareItems:(NSArray)items {

Q_UNUSED(sharingService);
Q_UNUSED(items);
//Some code here

}

- (void)sharingService:(NSSharingService )sharingService didFailToShareItems:(NSArray)items error:(NSError )error {

Q_UNUSED(sharingService);
Q_UNUSED(items);
Q_UNUSED(error);
//Some code here

}

- (void)sharingService:(NSSharingService)sharingService didShareItems:(NSArray )items {

Q_UNUSED(sharingService);
Q_UNUSED(items);
//Some code here

}

  1. pragma mark - Clear memory

- (void)dealloc {

[super dealloc];
[self.picker autorelease];
[self.onItemClicked release];
self.onItemClicked = nil;

}

end

p. More information you can find in official Apple documentation. And you need to see information about class NSSharingServicePickerDelegate.

Create QtQuick Item to use Share API from App.

p. Second class which you need to create is a class to call from C+. This class will call Objective-C/C. To do this you need follow a few steps:

  1. Create a new C+ class.
  2. Rename .cpp file to .mm and added it to "OBJECTIVE_SOURCES".
  3. Change .h file content to code:
#include <QtCore>
#include <QtQuick>

/'''*

class QfShareItem *

brief Manager to use share logic.
 *

author Andrew Shapovalov*/

class QfShareItem : public QQuickPaintedItem {

Q_OBJECT
Q_PROPERTY(QString shareString READ getShareString WRITE setShareString NOTIFY shareStringChanged)
Q_PROPERTY(QUrl shareUrl READ getShareUrl WRITE setShareUrl NOTIFY shareUrlChanged)
private:
/** The share string info.*/
QString m_shareString;
/* The share link.*/
QUrl m_shareUrl;

/*

brief Strip all HTML tags from string.
 *

param body The source string. *

return Plain text.
 *

author Andrew Shapovalov*/

QString stripHTMLTags(QString body);

/**

brief Works with all applications events.
 *

param obj The object which call event. *

param event The event of call.
 *

author Andrew Shapovalov*/

bool eventFilter(QObject* obj, QEvent* event);

/**

brief Share current content.
 *

author Andrew Shapovalov*/

void shareCurrentContent();
public:

/**

brief Create a new object.
 *

param parent Parent object. *

author Andrew Shapovalov*/
 explicit QfShareItem(QQuickPaintedItem '''parent = 0);

 //Others
 /'''*

brief Called when current object will redrawing. *

param painter The object for draw data.
 *

author Andrew Shapovalov*/

void paint(QPainter painter);
//Getters

/*

brief Get share content string.
 *

return Share string content. *

author Andrew Shapovalov*/
 inline QString getShareString(){return m_shareString;}

 /**

brief Get share url. *

return Share url.
 *

author Andrew Shapovalov*/

inline QUrl getShareUrl(){return m_shareUrl;}
//Setters

/**

brief Set share content string.
 *

param value Share string content. *

author Andrew Shapovalov*/
 inline void setShareString(QString value){m_shareString = value; emit shareStringChanged(m_shareString);}

 /**

brief Set share url. *

param value Share url.
 *

author Andrew Shapovalov*/

inline void setShareUrl(QUrl value){m_shareUrl = value; emit shareUrlChanged(m_shareUrl);}

/**

brief Share content and url.
 *

param text The text of share. *

param url The url to share.
 *

author Andrew Shapovalov*/

Q_INVOKABLE void shareContent(QString text = QString(), QUrl url = QUrl());
signals:

/**

brief Called when share content string was changed.
 *

param value Share string content. *

author Andrew Shapovalov*/
 void shareStringChanged(QString value);

 /**

brief Called when share url was changed. *

param value Share url.
 *

author Andrew Shapovalov*/

void shareUrlChanged(QUrl value);

/**

brief Called when user select share service.
 *

param serviceName The name of selected service. *

author Andrew Shapovalov*/
 void selectedService(QString serviceName);

 public slots:
};
  1. Change .mm file content to code:
#include "qfshareitem.h"
#include "qfsharepicker.h"

QString QfShareItem::stripHTMLTags(QString body)
{
 body.replace("<br>","");
 body.replace("</br>","");
 body.replace("</p>","");
 body.replace("</td>","");
 body.remove(QRegExp("<head>(.''')</head>"));
 body.remove(QRegExp("<form(.''')</form>"));
 body.remove(QRegExp( "<(.)[</sup>>]'''>"));

 return body.trimmed();
}

bool QfShareItem::eventFilter(QObject''' obj, QEvent* event)
{
 if(obj == this)
 {
 if(parentItem())
 {
 return QObject::eventFilter(parentItem(), event);
 }
 }

return QObject::eventFilter(obj, event);
}

void QfShareItem::shareCurrentContent()
{
 QQuickItem* parentItem = this->parentItem();
 if(!m_shareString.isEmpty() && parentItem)
 {
 QRectF rect = parentItem->mapRectToItem(NULL, parentItem->boundingRect());
 NSView* view = reinterpret_cast<NSView *>(parentItem->window()->winId());
 NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());

 m_shareString = m_shareString.replace("<style type=quot;text/cssquot;>a {color:#44a51c;text-decoration:none;}</style>", "");
 QString content = stripHTMLTags(m_shareString).trimmed();
 NSMutableArray* datas = [NSMutableArray arrayWithObject: content.toNSString()];
 if(!m_shareUrl.isEmpty())
 {
 NSURL* url = [NSURL URLWithString: m_shareUrl.toString().toNSString()];
 if(url)
 {
 [datas addObject: url];
 }
 }
 QfSharePicker* sharePicker = [[QfSharePicker alloc] initWithView:view frame:frame datasArray:datas onItemClicked:nil];
 [sharePicker autorelease];
 }
}

QfShareItem::QfShareItem(QQuickPaintedItem '''parent) :
 QQuickPaintedItem(parent)
{
 m_shareString.clear();
 m_shareUrl.clear();

 connect(this, &QQuickPaintedItem::parentChanged, [this](QQuickItem''' newParent){

 if(newParent)
 {
 newParent->setFiltersChildMouseEvents(true);
 }
 });
 this->installEventFilter(this);

setFlag(QQuickPaintedItem::ItemHasContents, true);
 setFlag(QQuickPaintedItem::ItemClipsChildrenToShape, true);
 setFlag(QQuickPaintedItem::ItemAcceptsDrops, true);
 setRenderTarget(QQuickPaintedItem::InvertedYFramebufferObject);
}

void QfShareItem::paint(QPainter *painter)
{
 try
 {
 Q_UNUSED(painter);
 }
 catch(std::exception& exception)
 {
 qDebug()<<"exception: "<<exception.what();
 }
}

void QfShareItem::shareContent(QString text, QUrl url)
{
 if(!text.isEmpty())
 {
 m_shareString = text;
 }

if(!url.isEmpty())
 {
 m_shareUrl = url;
 }

shareCurrentContent();
}
  1. Register new type to use in QML.
qmlRegisterType<YourShareItem>(uri, 1, 1, "YourShareItem");

How to use in QML.

Import the new type to your QML file where you need to use share logic and add this code:

  Button {
      id: btnLink
      width: 22
      height: 22
      
      onClicked: {
          share.shareContent();
      }
      
      QfShareItem {
          id: share
          anchors.fill: btnLink
          shareUrl: userPanelView.shareUrl
      }
  }

Summary