Skip to content
Permalink
Browse files

Add a generic search to button lists.

This adds back the incremental search in the lists that was lost during the switch to MythUI. While the old search was only available in MythMusic and MythGame this is available in all button lists including those used in the buttontree.

You access the search dialog using the new SEARCH (CTRL+S) keybinding while a buttonlist has the focus. The dialog allows you to enter a search string and also has find next and previous buttons. By default the search will search all text areas in a button item which works OK in most cases but some of the more complex button items like the ones in the playback recording screen require that the search be narrowed down to one or two text areas so there is a new MythButtonList::SetSearchFields(QString) function that takes a comma separated list of fields that should be searched. For example on the recording play back screen you want to search the "titlesubtitle" text area so you would call m_playbackList->SetSearchFields("titlesubtitle").

By default the popup will be displayed at the position set in the popups window definition which on some screens may obscure the list you are trying to search. I think the best people to decide where the popup should be displayed are the theme creators so there is a new optional <searchposition> element that can be added to the buttonlist definition that overrides the default popup position -  for example <searchposition>-1,400</searchposition> will display the popup horizontally centered and 400 down when the search dialog is shown for a button list with that in its definition.

Bumps the api version so a full recompile is required.
  • Loading branch information
Paul Harrison
Paul Harrison committed Jan 19, 2011
1 parent ff1066f commit a796d8b394fb6ff246a6edd9844616c9754e7cc0
@@ -11,7 +11,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythdb, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
#define MYTH_BINARY_VERSION "0.25.20110103-1"
#define MYTH_BINARY_VERSION "0.25.20110119-1"

/** \brief Increment this whenever the MythTV network protocol changes.
*
@@ -1064,6 +1064,8 @@ void MythMainWindow::InitKeys()
,"Copy text from textedit"), "Ctrl+C");
RegisterKey("Global", "PASTE", QT_TRANSLATE_NOOP("MythControls",
"Paste text into textedit"), "Ctrl+V");
RegisterKey("Global", "SEARCH", QT_TRANSLATE_NOOP("MythControls",
"Show incremental search dialog"), "Ctrl+S");

RegisterKey("Global", "0", QT_TRANSLATE_NOOP("MythControls","0"), "0");
RegisterKey("Global", "1", QT_TRANSLATE_NOOP("MythControls","1"), "1");
@@ -13,6 +13,9 @@
#include "mythmainwindow.h"
#include "mythuistatetype.h"
#include "lcddevice.h"
#include "mythuibutton.h"
#include "mythuitext.h"
#include "mythuitextedit.h"

#define LOC QString("MythUIButtonList(%1): ").arg(objectName())
#define LOC_ERR QString("MythUIButtonList(%1), Error: ").arg(objectName())
@@ -71,6 +74,10 @@ void MythUIButtonList::Const(void)
m_bottomRows = 0;
m_lcdTitle = "";

m_searchPosition = MythPoint(-2, -2);
m_searchFields = "**ALL**";
m_searchStartsWith = false;

m_upArrow = m_downArrow = NULL;

m_buttontemplate = NULL;
@@ -2190,6 +2197,36 @@ bool MythUIButtonList::keyPressEvent(QKeyEvent *e)
if (item)
emit itemClicked(item);
}
else if (action == "SEARCH")
{
MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");

SearchButtonListDialog *dlg = new SearchButtonListDialog(popupStack, "MythSearchListDialog", this, "");

if (dlg->Create())
{
if (m_searchPosition.x() != -2 || m_searchPosition.y() != -2)
{
int x = m_searchPosition.x();
int y = m_searchPosition.y();
QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
QRect dialogArea = dlg->GetArea();

if (x == -1)
x = (screenArea.width() - dialogArea.width()) / 2;

if (y == -1)
y = (screenArea.height() - dialogArea.height()) / 2;

dlg->SetPosition(x, y);
}

popupStack->AddScreen(dlg);
}
else
delete dlg;
}

else
handled = false;
}
@@ -2369,6 +2406,10 @@ bool MythUIButtonList::ParseElement(
m_drawFromBottom = parseBool(element);
m_alignment |= Qt::AlignBottom;
}
else if (element.tagName() == "searchposition")
{
m_searchPosition = parsePoint(element);
}
else
{
return MythUIType::ParseElement(filename, element, showWarnings);
@@ -2428,6 +2469,9 @@ void MythUIButtonList::CopyFrom(MythUIType *base)
m_clearing = false;
m_selPosition = m_topPosition = m_itemCount = 0;

m_searchPosition = lb->m_searchPosition;
m_searchFields = lb->m_searchFields;

MythUIType::CopyFrom(base);

m_upArrow = dynamic_cast<MythUIStateType *>(GetChild("upscrollarrow"));
@@ -2520,6 +2564,82 @@ void MythUIButtonList::updateLCD(void)
lcddev->switchToMenu(menuItems, m_lcdTitle);
}

bool MythUIButtonList::Find(const QString &searchStr, bool startsWith)
{
m_searchStr = searchStr;
m_searchStartsWith = startsWith;
return DoFind(false, true);
}

bool MythUIButtonList::FindNext(void)
{
return DoFind(true, true);
}

bool MythUIButtonList::FindPrev(void)
{
return DoFind(true, false);
}

bool MythUIButtonList::DoFind(bool doMove, bool searchForward)
{
if (m_searchStr.isEmpty())
return true;

int startPos = GetCurrentPos();
int currPos = startPos;
bool found = false;

if (doMove)
{
if (searchForward)
{
currPos++;

if (currPos >= GetCount())
currPos = 0;
}
else
{
currPos--;

if (currPos < 0)
currPos = GetCount() - 1;
}
}

while (true)
{
found = GetItemAt(currPos)->FindText(m_searchStr, m_searchFields, m_searchStartsWith);

if (found)
{
SetItemCurrent(currPos);
return true;
}

if (searchForward)
{
currPos++;

if (currPos >= GetCount())
currPos = 0;
}
else
{
currPos--;

if (currPos < 0)
currPos = GetCount() - 1;
}

if (startPos == currPos)
break;
}

return false;
}

//////////////////////////////////////////////////////////////////////////////

MythUIButtonListItem::MythUIButtonListItem(MythUIButtonList* lbtype,
@@ -2633,6 +2753,70 @@ QString MythUIButtonListItem::GetText(const QString &name) const
return QString();
}

bool MythUIButtonListItem::FindText(const QString &searchStr, const QString &fieldList,
bool startsWith) const
{
if (fieldList.isEmpty())
{
if (startsWith)
return m_text.startsWith(searchStr, Qt::CaseInsensitive);
else
return m_text.contains(searchStr, Qt::CaseInsensitive);
}
else if (fieldList == "**ALL**")
{
if (startsWith)
{
if (m_text.startsWith(searchStr, Qt::CaseInsensitive))
return true;
}
else
{
if (m_text.contains(searchStr, Qt::CaseInsensitive))
return true;
}

QMap<QString, TextProperties>::const_iterator i = m_strings.constBegin();
while (i != m_strings.constEnd())
{
if (startsWith)
{
if (i.value().text.startsWith(searchStr, Qt::CaseInsensitive))
return true;
}
else
{
if (i.value().text.contains(searchStr, Qt::CaseInsensitive))
return true;
}

++i;
}
}
else
{
QStringList fields = fieldList.split(',', QString::SkipEmptyParts);
for (int x = 0; x < fields.count(); x++)
{
if (m_strings.contains(fields.at(x).trimmed()))
{
if (startsWith)
{
if (m_strings[fields.at(x)].text.startsWith(searchStr, Qt::CaseInsensitive))
return true;
}
else
{
if (m_strings[fields.at(x)].text.contains(searchStr, Qt::CaseInsensitive))
return true;
}
}
}
}

return false;
}

void MythUIButtonListItem::SetFontState(const QString &state,
const QString &name)
{
@@ -2974,3 +3158,96 @@ void MythUIButtonListItem::SetToRealButton(MythUIStateType *button, bool selecte

m_parent->ItemVisible(this);
}

//---------------------------------------------------------
// SearchButtonListDialog
//---------------------------------------------------------
SearchButtonListDialog::SearchButtonListDialog(MythScreenStack *parent, const char *name,
MythUIButtonList *parentList, QString searchText)
: MythScreenType(parent, name, false)
{
m_parentList = parentList;
m_searchText = searchText;
m_startsWith = false;
}

SearchButtonListDialog::~SearchButtonListDialog(void)
{
}

bool SearchButtonListDialog::Create(void)
{
if (!CopyWindowFromBase("MythSearchListDialog", this))
return false;

bool err = false;
UIUtilE::Assign(this, m_searchEdit, "searchedit", &err);
UIUtilE::Assign(this, m_prevButton, "prevbutton", &err);
UIUtilE::Assign(this, m_nextButton, "nextbutton", &err);
UIUtilW::Assign(this, m_searchState, "searchstate");

if (err)
{
VERBOSE(VB_IMPORTANT, "Cannot load screen 'MythSearchListDialog'");
return false;
}

m_searchEdit->SetText(m_searchText);

connect(m_searchEdit, SIGNAL(valueChanged()), SLOT(searchChanged()));
connect(m_prevButton, SIGNAL(Clicked()), SLOT(prevClicked()));
connect(m_nextButton, SIGNAL(Clicked()), SLOT(nextClicked()));

BuildFocusList();

return true;
}

bool SearchButtonListDialog::keyPressEvent(QKeyEvent *event)
{
QStringList actions;
bool handled = GetMythMainWindow()->TranslateKeyPress("Music", event, actions, false);

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

if (action == "0")
{
m_startsWith = !m_startsWith;
searchChanged();
}
else
handled = false;
}

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

return handled;
}

void SearchButtonListDialog::searchChanged(void)
{
bool found = m_parentList->Find(m_searchEdit->GetText(), m_startsWith);

if (m_searchState)
m_searchState->DisplayState(found ? "found" : "notfound");
}

void SearchButtonListDialog::nextClicked(void)
{
bool found = m_parentList->FindNext();

if (m_searchState)
m_searchState->DisplayState(found ? "found" : "notfound");
}

void SearchButtonListDialog::prevClicked(void)
{
bool found = m_parentList->FindPrev();

if (m_searchState)
m_searchState->DisplayState(found ? "found" : "notfound");
}

0 comments on commit a796d8b

Please sign in to comment.
You can’t perform that action at this time.