emailuis/nmailui/src/nmeditorcontent.cpp
changeset 47 f83bd4ae1fe3
parent 44 c2d07d913565
child 48 10eaf342f539
equal deleted inserted replaced
45:780f926bc26c 47:f83bd4ae1fe3
    17 
    17 
    18 #include "nmuiheaders.h"
    18 #include "nmuiheaders.h"
    19 
    19 
    20 // Layout
    20 // Layout
    21 static const char *NMUI_EDITOR_BODY = "BodyTextEdit";
    21 static const char *NMUI_EDITOR_BODY = "BodyTextEdit";
    22 
    22 static const char *NMUI_EDITOR_SCROLL_AREA = "scrollArea";
       
    23 static const char *NMUI_EDITOR_SCROLL_AREA_CONTENTS = "scrollAreaContents";
       
    24 
       
    25 // Regular expression for selecting img tags with "cid" in the mail.
       
    26 static const char *NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG = 
       
    27     "(<img (src\\s*=\\s*)(.{0,1}cid)([^<]+)(>\\s*|/>\\s*|></img>\\s*))";
       
    28 	
    23 /*!
    29 /*!
    24     Constructor
    30     Constructor
    25 */
    31 */
    26 NmEditorContent::NmEditorContent(QGraphicsItem *parent,
    32 NmEditorContent::NmEditorContent(QObject *parent,
    27                                  NmEditorView *parentView,
       
    28                                  HbDocumentLoader *documentLoader,
    33                                  HbDocumentLoader *documentLoader,
    29                                  QNetworkAccessManager &manager) :
    34                                  QNetworkAccessManager &manager,
    30     HbWidget(parent),
    35                                  NmApplication &application) :
       
    36     QObject(parent),
    31     mHeaderWidget(NULL),
    37     mHeaderWidget(NULL),
    32     mParentView(parentView),
    38     mMessageBodyType(NmPlainText),
    33     mEditorLayout(NULL),
       
    34     mMessageBodyType(PlainText),
       
    35     mEditorWidget(NULL),
    39     mEditorWidget(NULL),
    36     mBackgroundScrollArea((NmBaseViewScrollArea*)parent)
    40     mScrollArea(NULL),
    37 {
    41     mScrollAreaContents(NULL),
    38     NM_FUNCTION;
    42     mApplication(application)
    39 
    43 {
    40     // Add header area handling widget into layout
    44     NM_FUNCTION;
    41     mHeaderWidget = new NmEditorHeader(documentLoader);
    45 
       
    46     // Construct container for the header widgets
       
    47     mHeaderWidget = new NmEditorHeader(this, documentLoader);
    42 
    48 
    43     // Get pointer to body text area handling widget
    49     // Get pointer to body text area handling widget
    44     mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY));
    50     mEditorWidget = qobject_cast<NmEditorTextEdit *>(documentLoader->findWidget(NMUI_EDITOR_BODY));
    45     
    51     
    46     // Set body editor to use NmEditorTextDocument
    52     // Set body editor to use NmEditorTextDocument
    47     NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager);
    53     NmEditorTextDocument *textDocument = new NmEditorTextDocument(manager);
    48     mEditorWidget->setDocument(textDocument); 
    54     mEditorWidget->setDocument(textDocument); 
    49     textDocument->setParent(mEditorWidget); // ownership changes
    55     textDocument->setParent(mEditorWidget); // ownership changes
    50 
    56 
    51     mEditorWidget->init(mBackgroundScrollArea);
    57     mScrollArea = qobject_cast<NmBaseViewScrollArea *>
    52     // we are interested in the editor widget's height changes
    58         (documentLoader->findObject(NMUI_EDITOR_SCROLL_AREA));
    53     connect(mEditorWidget, SIGNAL(editorContentHeightChanged()), this,
       
    54         SLOT(setEditorContentHeight()));
       
    55 
    59 
    56     // Enable style picker menu item.
    60     // Enable style picker menu item.
    57     mEditorWidget->setFormatDialog(new HbFormatDialog());
    61     mEditorWidget->setFormatDialog(new HbFormatDialog());
    58 
    62 
       
    63     mScrollAreaContents =
       
    64         qobject_cast<HbWidget *>(documentLoader->findWidget(NMUI_EDITOR_SCROLL_AREA_CONTENTS));
       
    65     
    59     // Create signal slot connections
    66     // Create signal slot connections
    60     createConnections();
    67     createConnections();
    61 }
    68 }
    62 
    69 
    63 /*!
    70 /*!
    64     Destructor
    71     Destructor
    65 */
    72 */
    66 NmEditorContent::~NmEditorContent()
    73 NmEditorContent::~NmEditorContent()
    67 {
    74 {
    68     NM_FUNCTION;
    75     NM_FUNCTION;
    69     
       
    70    delete mHeaderWidget;
       
    71 }
    76 }
    72 
    77 
    73 /*!
    78 /*!
    74     Fill message data into header and body fileds. If reply envelopw is
    79     Fill message data into header and body fileds. If reply envelopw is
    75     present, reply header is generated and set to editor. Reply
    80     present, reply header is generated and set to editor. Reply
    76     envelope ownership is not transferred here.
    81     envelope ownership is not transferred here.
    77  */
    82  */
    78 void NmEditorContent::setMessageData(const NmMessage &originalMessage,
    83 void NmEditorContent::setMessageData(const NmMessage &originalMessage, 
    79                                      bool createReplyHeader)
    84                                      NmUiEditorStartMode &editorStartMode)
    80 {
    85 {
    81     NM_FUNCTION;
    86     NM_FUNCTION;
    82     
    87     
    83     QString bodyContent;
    88     QString bodyContent;
    84     
    89     
    85     // We create the "reply" header (also for forward message), but not to draft message.
    90     // Create the "reply" header (also for forward message)
    86     if (mEditorWidget && createReplyHeader) {          
    91     if (editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll || 
    87         QTextCursor cursor = mEditorWidget->textCursor();
    92         editorStartMode==NmUiEditorForward) {
    88         cursor.setPosition(0);
    93         bodyContent.append(NmUtilities::createReplyHeader(originalMessage.envelope()));
    89         cursor.insertHtml(NmUtilities::createReplyHeader(originalMessage.envelope()));
    94     }
    90     }
       
    91     // Take reply header as html format.
       
    92     bodyContent.append(mEditorWidget->toHtml());
       
    93     
    95     
    94     // Check which part is present. Html or plain text part. We use the original message parts.
    96     // Check which part is present. Html or plain text part. We use the original message parts.
    95     const NmMessagePart *htmlPart = originalMessage.htmlBodyPart();
    97     const NmMessagePart *htmlPart = originalMessage.htmlBodyPart();
    96     const NmMessagePart *plainPart = originalMessage.plainTextBodyPart();
    98     const NmMessagePart *plainPart = originalMessage.plainTextBodyPart();
    97  
    99  
    98     if (htmlPart && mEditorWidget) {
   100     if (htmlPart) {
    99         bodyContent.append(htmlPart->textContent());
   101         bodyContent.append(htmlPart->textContent());
       
   102         if(editorStartMode==NmUiEditorReply || editorStartMode==NmUiEditorReplyAll ) {
       
   103             removeEmbeddedImages(bodyContent);
       
   104         }
   100         emit setHtml(bodyContent);
   105         emit setHtml(bodyContent);
   101         mMessageBodyType = HTMLText;
   106         mMessageBodyType = NmHTMLText;
   102     }
   107     }
   103     else if (plainPart) {
   108     else if (plainPart) {
   104         // Plain text part was present, set it to HbTextEdit
   109         // Plain text part was present, set it to HbTextEdit
   105         bodyContent.append(plainPart->textContent());
   110         bodyContent.append(plainPart->textContent());
   106         emit setPlainText(bodyContent);
   111         emit setPlainText(bodyContent);
   107         mMessageBodyType = PlainText;
   112         mMessageBodyType = NmPlainText;
   108     }
   113     }
   109 }  
   114 }  
   110 
   115 
   111 /*!
   116 /*!
   112    This method set new height for the editor content when header or body field
       
   113    height has been changed.
       
   114  */
       
   115 void NmEditorContent::setEditorContentHeight()
       
   116 {
       
   117     NM_FUNCTION;
       
   118     
       
   119 	const QSizeF reso = HbDeviceProfile::current().logicalSize();
       
   120     qreal containerHeight = mEditorWidget->contentHeight() + mHeaderWidget->headerHeight();
       
   121     if (containerHeight < reso.height()) {
       
   122         //Currently content height is too long because Chrome hiding is not supported.
       
   123         //Fix this when Chrome works.
       
   124         containerHeight = reso.height();
       
   125         qreal bodyContentHeight =
       
   126             reso.height() - mHeaderWidget->headerHeight();
       
   127         mEditorWidget->setPreferredHeight(bodyContentHeight);
       
   128         mEditorWidget->setMaximumHeight(bodyContentHeight);
       
   129     }
       
   130     mParentView->scrollAreaContents()->setMinimumHeight(containerHeight);
       
   131     mParentView->scrollAreaContents()->setMaximumHeight(containerHeight);
       
   132     mBackgroundScrollArea->setMaximumHeight(containerHeight);
       
   133 }
       
   134 
       
   135 /*!
       
   136    This method creates all needed signal-slot connections
   117    This method creates all needed signal-slot connections
   137  */
   118  */
   138 void NmEditorContent::createConnections()
   119 void NmEditorContent::createConnections()
   139 {
   120 {
   140     NM_FUNCTION;
   121     NM_FUNCTION;
   141     
   122     
   142     // Body edit widget is also interested about bg scroll position change
       
   143     connect(mBackgroundScrollArea, SIGNAL(scrollPositionChanged(QPointF)),
       
   144             mEditorWidget, SLOT(updateScrollPosition(QPointF)));
       
   145     // Signal for setting HbTextEdit widgets html content
   123     // Signal for setting HbTextEdit widgets html content
   146     connect(this, SIGNAL(setHtml(QString)),
   124     connect(this, SIGNAL(setHtml(QString)),
   147             mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection);
   125             mEditorWidget, SLOT(setHtml(QString)), Qt::QueuedConnection);
       
   126 
   148     // Signal for setting HbTextEdit widgets plain text content
   127     // Signal for setting HbTextEdit widgets plain text content
   149     connect(this, SIGNAL(setPlainText(QString)),
   128     connect(this, SIGNAL(setPlainText(QString)),
   150             mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection);
   129             mEditorWidget, SLOT(setPlainText(QString)), Qt::QueuedConnection);
       
   130 
   151     // Inform text edit widget that header height has been changed
   131     // Inform text edit widget that header height has been changed
   152     connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)),
   132     connect(mHeaderWidget, SIGNAL(headerHeightChanged(int)), this, SLOT(setEditorContentHeight()),
   153             mEditorWidget, SLOT(setHeaderHeight(int)));
   133         Qt::QueuedConnection);
       
   134 
       
   135     // we are interested in the document's height changes
       
   136     connect(mEditorWidget->document()->documentLayout(), SIGNAL(documentSizeChanged(QSizeF)), this,
       
   137         SLOT(setEditorContentHeight()), Qt::QueuedConnection);
       
   138 
       
   139     // We need to update the scroll position according the editor cursor position
       
   140     connect(mEditorWidget, SIGNAL(cursorPositionChanged(int, int)), this, 
       
   141         SLOT(setScrollPosition(int, int)), Qt::QueuedConnection);
       
   142     
       
   143     // We need to know the scroll area's current position for calculating the new position in
       
   144 	// setScrollPosition
       
   145     connect(mScrollArea, SIGNAL(scrollPositionChanged(QPointF)), this, 
       
   146         SLOT(updateScrollPosition(QPointF)), Qt::QueuedConnection);
   154 }
   147 }
   155 
   148 
   156 /*!
   149 /*!
   157     Return pointer to the email body text edit widget
   150     Return pointer to the email body text edit widget
   158  */
   151  */
   159 NmEditorTextEdit* NmEditorContent::editor() const
   152 NmEditorTextEdit *NmEditorContent::editor() const
   160 {
   153 {
   161     NM_FUNCTION;
   154     NM_FUNCTION;
   162     
   155     
   163     return mEditorWidget;
   156     return mEditorWidget;
   164 }
   157 }
   165 
   158 
   166 /*!
   159 /*!
   167     Return pointer to the header widget
   160     Return pointer to the header widget
   168  */
   161  */
   169 NmEditorHeader* NmEditorContent::header() const
   162 NmEditorHeader *NmEditorContent::header() const
   170 {
   163 {
   171     NM_FUNCTION;
   164     NM_FUNCTION;
   172     
   165     
   173     return mHeaderWidget;
   166     return mHeaderWidget;
   174 }
   167 }
   175 
   168 
       
   169 /*!
       
   170     This slot is called when header widget height has been changed. Function performs
       
   171     the repositioning of the body field and resizing of the editor and content area.
       
   172  */
       
   173 void NmEditorContent::setEditorContentHeight()
       
   174 {
       
   175     NM_FUNCTION;
       
   176     
       
   177     qreal topMargin = 0;
       
   178     HbStyle().parameter("hb-param-margin-gene-top", topMargin);
       
   179     
       
   180     // header height
       
   181     qreal headerHeight = mHeaderWidget->headerHeight();
       
   182 
       
   183     // body area editor's document height with margins added
       
   184     qreal documentHeightAndMargins = mEditorWidget->document()->size().height() +
       
   185         (mEditorWidget->document()->documentMargin() * 2);
       
   186 
       
   187     // get the chrome height
       
   188     qreal chromeHeight = 0;
       
   189     HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight);
       
   190     
       
   191     qreal toolbarHeight = 0;
       
   192     HbStyle().parameter("hb-param-widget-toolbar-height", toolbarHeight);
       
   193 
       
   194     // screen height
       
   195     qreal screenHeight = mApplication.screenSize().height();
       
   196 
       
   197     // set min size for the body area so that at least the screen area is always filled
       
   198     qreal bodyAreaMinSize = screenHeight - chromeHeight - topMargin - headerHeight;
       
   199     
       
   200     qreal bodyAreaSize = fmax(bodyAreaMinSize, documentHeightAndMargins);
       
   201 
       
   202     mScrollAreaContents->setPreferredHeight(topMargin + headerHeight + bodyAreaSize);
       
   203 }
       
   204 
       
   205 /*!
       
   206     This slot is called when cursor position is changed in body area using
       
   207     'pointing stick' or keyboard. Function will update the scroll position
       
   208     of the content so that cursor does not go outside of the screen or
       
   209     behind the virtual keyboard.
       
   210  */
       
   211 void NmEditorContent::setScrollPosition(int oldPos, int newPos)
       
   212 {
       
   213     NM_FUNCTION;
       
   214     
       
   215     Q_UNUSED(oldPos);
       
   216 
       
   217     qreal chromeHeight = 0;
       
   218     HbStyle().parameter("hb-param-widget-chrome-height", chromeHeight);
       
   219     
       
   220     const QSizeF screenReso = mApplication.screenSize();
       
   221     qreal maxHeight = screenReso.height() - chromeHeight;
       
   222 
       
   223     // Get cursor position coordinates
       
   224     QRectF cursorPosPix = mEditorWidget->rectForPosition(newPos);
       
   225     
       
   226     // Calculate the screen top and bottom boundaries, this means the part of the
       
   227     // background scroll area which is currently visible.
       
   228     qreal visibleRectTopBoundary;
       
   229     qreal visibleRectBottomBoundary;
       
   230     
       
   231     qreal headerHeight = mHeaderWidget->headerHeight();
       
   232 
       
   233     if (mScrollPosition.y() < headerHeight) {
       
   234         // Header is completely or partially visible
       
   235         visibleRectTopBoundary = headerHeight - mScrollPosition.y();
       
   236         visibleRectBottomBoundary = maxHeight - visibleRectTopBoundary;
       
   237     }
       
   238     else {
       
   239         // Header is not visible
       
   240         visibleRectTopBoundary = mScrollPosition.y() - headerHeight;
       
   241         visibleRectBottomBoundary = visibleRectTopBoundary + maxHeight;
       
   242     }
       
   243 
       
   244     // Do scrolling if cursor is out of the screen boundaries
       
   245     if (cursorPosPix.y() > visibleRectBottomBoundary) {
       
   246         // Do scroll forward
       
   247         mScrollArea->scrollContentsTo(QPointF(0, cursorPosPix.y() - maxHeight + headerHeight));
       
   248     }
       
   249     else if (cursorPosPix.y() + headerHeight < mScrollPosition.y()) {
       
   250         // Do scroll backward
       
   251         mScrollArea->scrollContentsTo(QPointF(0, cursorPosPix.y() + headerHeight));
       
   252     }
       
   253 }
       
   254 
       
   255 /*!
       
   256     This slot is called when background scroll areas scroll position has been shanged.
       
   257 */
       
   258 void NmEditorContent::updateScrollPosition(const QPointF &newPosition)
       
   259 {
       
   260     NM_FUNCTION;
       
   261     
       
   262     mScrollPosition = newPosition;
       
   263 }
       
   264 
       
   265 /*!
       
   266     Removes embedded images from the message body
       
   267  */
       
   268 void NmEditorContent::removeEmbeddedImages(QString &bodyContent)
       
   269 {
       
   270     NM_FUNCTION;
       
   271  
       
   272     QRegExp regExp(NMUI_EDITOR_REMOVE_EMBD_IMAGES_REG, Qt::CaseInsensitive);
       
   273     bodyContent.remove(regExp);
       
   274 }