Building Plugins:MythNotes04

From MythTV Official Wiki
Jump to: navigation, search

Shows list structure of objects stored in DB.

  • ButtonList
  • Popup window


Important.png Note: Read the MythNotes introduction Building_Plugins:MythNotes first.

Important.png Note: This tutorial follows-up the Building_Plugins:MythNotes02 tutorial.

C++ code

In MythTV you can either create all your windows by yourself or use the predefined popup windows:

  • DialogCompletionEvent
  • MythDialogBox
  • MythConfirmationDialog
  • MythTextInputDialog
  • MythUISearchDialog

(see the "mythtv-svn-trunk/mythtv/libs/libmythui/mythdialogbox.h" for details)

The idea is to create new window over the current one. When completed get the results. To do so QEvent custom events are used notify previous window about the result availability.

Another new element is MythUIButtonList. In XML file is defined by area, spacing and layout (MythUI_Theme_Development). In C++ code they are assigned with MythUIButtonList variable and are created as clean. You need to create buttons (MythUIButtonListItem object with desired list as it's parent). Each button is able to store QVariant value. For details see the "mythtv-svn-trunk/mythtv/libs/libmythui/mythuibuttonlist.h".


Script.png /mythnotes/main.cpp

/*
 * Main of MythTV's demonstration plugin MythNotes
 *
 * Copyright (C) 2010 Lukas Doktor <ldoktor@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License
 * as published by the Free Software Foundation.
 *
 */

#include <iostream>
using namespace std;

#include <QApplication>

#include "notesUI.h"

#include <mythversion.h>
#include <mythpluginapi.h>
#include <mythscreentype.h>
#include <mythuihelper.h>
#include <mythmainwindow.h>
#include <mythcontext.h>


#define LOC_ERR QString("MythNotes:MAIN Error: ")
#define LOC_WARN QString("MythNotes:MAIN Warning: ")
#define LOC QString("MythNotes:MAIN: ")

/* Main program run wrappers */
void runNotes(void);
int  RunNotes(void);

void setupKeys(void)
{
    REG_JUMP("MythNotes", QT_TRANSLATE_NOOP("MythControls",
        "Notes taking demonstration plugin"), "", runNotes);
    REG_KEY("MythNotes", "EXIT", QT_TRANSLATE_NOOP("MythControls",
    	"Exit the Smart Home"), "Q");
    REG_KEY("MythNotes", "MENU", QT_TRANSLATE_NOOP("MythControls",
    	"Delete note"), "M");
}

/* plugin initialization */
int mythplugin_init(const char *libversion)
{
	VERBOSE(VB_IMPORTANT, LOC + "init");
    if (!gContext->TestPopupVersion("mythnotes", libversion,
                                    MYTH_BINARY_VERSION))
    {
        VERBOSE(VB_IMPORTANT,
                QString("libmythnotes.so/main.o: binary version mismatch"));
        return -1;
    }

    setupKeys();

    return 0;
}

void runNotes(void)
{
    RunNotes();
}

int RunNotes(void)
{
    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
    NotesUI *notes = new NotesUI(mainStack, "Notes");
    
    if (notes->Create())
    {
        mainStack->AddScreen(notes);
        return 0;
    } else {
        delete notes;
        return -1;
    }
}

/* plugin execution */
int mythplugin_run(void)
{
	VERBOSE(VB_IMPORTANT, LOC + "exec");
    return RunNotes();
}

/* plugin config execution */
int mythplugin_config(void)
{
	VERBOSE(VB_IMPORTANT, LOC + "config");
    MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
    NotesUISettings *notes = new NotesUISettings(mainStack);

    if (notes->Create())
    {
        mainStack->AddScreen(notes);
        return 0;
    } else {
        delete notes;
        return -1;
    }
}

/* plugin clean-up */
void mythplugin_destroy(void)
{
	VERBOSE(VB_IMPORTANT, LOC + "destroy");
}
  • minor changes you already know


Script.png /mythnotes/notesUI.h

/*
 * Header file for UI
 *
 * Copyright (C) 2010 Lukas Doktor <ldoktor@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License
 * as published by the Free Software Foundation.
 *
 */

#ifndef NOTESUI_H_
#define NOTESUI_H_

#include <QString>
#include <QKeyEvent>

#include <mythscreentype.h>
#include <mythmainwindow.h>
#include <mythdialogbox.h>
#include <mythuibutton.h>
#include <mythuibuttonlist.h>
#include <mythdb.h>
#include <mythverbose.h>
#include <mythcontext.h>


class MythUIButton;
class MythUIButtonList;
class MythUIButtonListItem;
class MythUIText;
class MythUITextEdit;
class QKeyEvent;
class QEvent;

class NotesUI : public MythScreenType
{
	Q_OBJECT

  public:
	NotesUI(MythScreenStack *parentStack, QString name = "MythNotes");
	bool Create();
	bool keyPressEvent(QKeyEvent *event);
	void customEvent(QEvent *event);

	bool editDialog(QString text = NULL);
	bool menuDialog();

  private:
	MythUIText			*m_title;
	MythUIText			*m_details;
	MythUIButtonList	*m_notes;

  private slots:
  	void notesCallback(MythUIButtonListItem *item);
  	void selectNotesCallback(MythUIButtonListItem *item);
	void closeCallback();
};

class NotesUISettings : public MythScreenType
{
	Q_OBJECT

  public:
	NotesUISettings(MythScreenStack *parentStack);
	bool Create();

  private:
	MythUIButton	*m_clearBtn;
  private slots:
	void clearCallback();
};

#endif /* NOTESUI_H_ */
  • minor changes (variables, slots, ...)


Script.png /mythnotes/notesUI.cpp

/*
 * Source file for UIs
 *
 * Copyright (C) 2010 Lukas Doktor <ldoktor@redhat.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License
 * as published by the Free Software Foundation.
 *
 */

#include "notesUI.h"

#define LOC_ERR QString("MythNotes:notesUI Error: ")
#define LOC_WARN QString("MythNotes:notesUI Warning: ")
#define LOC QString("MythNotes:notesUI: ")

NotesUI::NotesUI(MythScreenStack *parent, QString name)
		: MythScreenType(parent, name), m_title(NULL),
		  m_details(NULL)
{
	m_notes = NULL;
}

bool NotesUI::Create()
{
	if (!LoadWindowFromXML("notes-ui.xml", "notesui", this))
		return false;

	bool err = false;
	UIUtilE::Assign(this, m_title, "title", &err);
	UIUtilE::Assign(this, m_notes, "notes", &err);
	UIUtilE::Assign(this, m_details, "details", &err);
	if (err)
		return false;


	connect(m_notes, SIGNAL(itemClicked(MythUIButtonListItem*)),
			this, SLOT(notesCallback(MythUIButtonListItem*)));
	connect(m_notes, SIGNAL(itemSelected(MythUIButtonListItem*)),
			this, SLOT(selectNotesCallback(MythUIButtonListItem*)));

	BuildFocusList();
	new MythUIButtonListItem(m_notes, "Add Note");
	new MythUIButtonListItem(m_notes, "Close MythNote");
	SetFocusWidget(m_notes);

	m_details->SetText("");

	return true;
}

bool NotesUI::keyPressEvent(QKeyEvent *event)
{
    if (GetFocusWidget()->keyPressEvent(event))
        return true;

    bool handled = false;
    QStringList actions;
    handled = GetMythMainWindow()->TranslateKeyPress("MythNotes", event, actions);

    for (int i = 0; i < actions.size() && !handled; i++)
    {
        QString action = actions[i];
        handled = true;

        if (action == "ESCAPE") {
        	closeCallback();
        } else if (action == "MENU") {
        	menuDialog();
        } else {
            handled = false;
        }
    }

    if (!handled && MythScreenType::keyPressEvent(event))
        handled = true;

    return handled;
}

void NotesUI::customEvent(QEvent *event)
{
	if (event->type() == DialogCompletionEvent::kEventType)
	{
		DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);

		if (dce->GetId() == "newNote")
		{
			MythUIButtonListItem *newItem =
					new MythUIButtonListItem(m_notes, dce->GetResultText());
			newItem->SetData(dce->GetResultText());
		} else if (dce->GetId() == "editNote") {
			m_notes->GetItemCurrent()->SetData(dce->GetResultText());
			m_notes->GetItemCurrent()->SetText(dce->GetResultText());
		} else if (dce->GetId() == "menu") {
			switch (dce->GetResult()) {
			case 0: { //Edit
				editDialog(m_notes->GetItemCurrent()->GetData().toString());
				break;	}
			case 1: { //Delete
				delete m_notes->GetItemCurrent();
				break;	}
			case 2: { //Exit
				closeCallback();
				break;	}
			}
		}
	}
}

bool NotesUI::editDialog(QString text)
{
	MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");

	if (text.isNull()) { //NEW
		MythTextInputDialog *dialog =
				new MythTextInputDialog(popupStack,
										"Insert your note");
		if (dialog->Create()) {
			popupStack->AddScreen(dialog);
			dialog->SetReturnEvent(this, "newNote");
		} else {
			delete dialog;
			return 0;
		}
	} else { //EDIT
		MythTextInputDialog *dialog =
				new MythTextInputDialog(popupStack,
										"Edit the note",
										(InputFilter)0,
										false,
										text);
		if (dialog->Create()) {
			popupStack->AddScreen(dialog);
			dialog->SetReturnEvent(this, "editNote");
		} else {
			delete dialog;
			return 0;
		}
	}
	return 1;
}

bool NotesUI::menuDialog()
{
	MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
	MythDialogBox *dialog = new MythDialogBox("Menu", popupStack, "menu");

	if (dialog->Create()) {
		popupStack->AddScreen(dialog);
		dialog->SetReturnEvent(this, "menu");
		dialog->AddButton("Edit Note");
		dialog->AddButton("Delete Note");
		dialog->AddButton("Exit MythNotes");
	} else {
		delete dialog;
		return 0;
	}
	return 1;
}

void NotesUI::notesCallback(MythUIButtonListItem *item)
{
	if (m_notes->GetCurrentPos() == 0) {
		editDialog(NULL);
	} else if (m_notes->GetCurrentPos() == 1) {
		closeCallback();
	} else {
		menuDialog();
	}
}

void NotesUI::selectNotesCallback(MythUIButtonListItem *item)
{
	if (m_notes->GetCurrentPos() < 2) {
		m_details->SetText("");
	} else {
		m_details->SetText(item->GetData().toString());
	}
}

void NotesUI::closeCallback()
{
	Close();
}



NotesUISettings::NotesUISettings(MythScreenStack *parent)
				: MythScreenType(parent, "Notes UI Settings"), m_clearBtn(NULL)
{
}

bool NotesUISettings::Create()
{
	if (!LoadWindowFromXML("notes-ui.xml", "notesuisettings", this))
		return false;

	bool err = false;
	UIUtilE::Assign(this, m_clearBtn, "clearbtn", &err);
	if (err)
		return false;

	connect(m_clearBtn, SIGNAL(Clicked()), this, SLOT(clearCallback()));

	BuildFocusList();
	SetFocusWidget(m_clearBtn);

	return true;
}

void NotesUISettings::clearCallback()
{
}
  • NotesUI::Create()
    • creates the control buttons
  • NotesUI::customEvent()
    • Custom handling of general QEvent
    • Used to handle the DialogCompletionEvent
    • Different windows are differentiated by ID (name)
  • NotesUI::editDialog
    • Either creates edit or add window
    • Similarly to main.cpp it creates a window and if succeeds it shows it in popup stack (over the actual window)
  • NotesUI::menuDialog()
    • Another kind of window. Notice that you can/have to specify multiple buttons thus it's very flexible.

UI files

Script.png /themes/default/notes-ui.xml

<?xml version="1.0" encoding="utf-8"?>
<mythuitheme>
    <window name="notesui">
        <textarea name="title">
            <area>10,10,780,60</area>
            <font>baselarge</font>
            <align>allcenter</align>
            <multiline>yes</multiline>
            <value>MythNotes</value>
        </textarea>

        <buttonlist name="notes" from="basebuttonlist">
        	<area>10,80,395,510</area>
        	<buttonarea>0,0,100%,100%</buttonarea>
        	<layout>vertical</layout>
        	<align>center</align>
        	<arrange>stack</arrange>
        	<statetype name="buttonitem">
        		<area>0,0,100%,30</area>
        	</statetype>
        	<showarrow>no</showarrow>
        </buttonlist>
        
        <textarea name="details">
        	<area>405,80,395,510</area>
        	<font>basemedium</font>
        	<align>top,left</align>
        	<multiline>yes</multiline>
        </textarea>
    </window>
    
    <window name="notesuisettings">
    	<textarea name="title">
            <area>10,10,780,60</area>
            <font>baselarge</font>
            <align>allcenter</align>
            <multiline>yes</multiline>
            <value>Notes Settings</value>
        </textarea>
    </window>
</mythuitheme>
  • Instead of multiple buttons use the buttonlists.

Remaining files

No changes here

Compile & Run

See the first part Building_Plugins:MythNotes00.

Recapitulation

  • copy the plug-in from the first part (Building_Plugins:MythNotes03)
  • Modify the C++ code (includes, init, windows, QEvents)
  • Modify the XML UI layout (ButtonLists - from="basebuttonlist")

Next tutorial

Important.png Note: You have successfully finished the Advanced UI tutorial. Let's move on to the next level - "Advanced SQL storage" (Building_Plugins:MythNotes05)