Subject: [BeOS] Spelling dialog / support
From: Christopher Plymire (chrisjp@eudoramail.com)
Date: Tue Jul 25 2000 - 06:30:34 CDT
Finished spelling dialog resource.
Created code neccesary to operate the dialog correctly under BeOS.
spell.rsrc and should be inserted in /abi/src/wp/main/beos -- needs to 
be marked as binary.
I've included diffs of the files neccesary to hook up these dialogs.
-Christopher
--- /windisk/abiword/abi/src/wp/ap/beos/ap_BeOSDialog_Spell.cpp	Wed Jul 26 13:20:02 2000
+++ ap_BeOSDialog_Spell.cpp	Tue Jul 25 11:26:26 2000
@@ -32,6 +32,40 @@
 
 #include "ut_Rehydrate.h"
 
+// We really shouldn't unlock the window lock, but the redraw when we focus on the next
+// misspelled word will deadlock if we don't..
+
+status_t WaitForDelete(sem_id blocker)
+{
+	status_t	result;
+	thread_id	this_tid = find_thread(NULL);
+	BLooper		*pLoop;
+	BWindow		*pWin = 0;
+
+	pLoop = BLooper::LooperForThread(this_tid);
+	if (pLoop)
+		pWin = dynamic_cast<BWindow*>(pLoop);
+
+	// block until semaphore is deleted (modal is finished)
+	if (pWin) {
+		do {
+			// update the window periodically
+			pWin->Unlock(); // Who will know?=)
+			snooze(100);
+			pWin->Lock();
+			
+			pWin->UpdateIfNeeded();
+			result = acquire_sem_etc(blocker, 1, B_TIMEOUT, 1000);
+		} while (result != B_BAD_SEM_ID);
+	} else {
+		do {
+			// just wait for exit
+			result = acquire_sem(blocker);
+		} while (result != B_BAD_SEM_ID);
+	}
+	return result;
+}
+
 /*****************************************************************/
 
 class SpellWin:public BWindow {
@@ -42,57 +76,380 @@
                 virtual bool QuitRequested(void);
                 
         private:
-                int                     spin;
                 AP_BeOSDialog_Spell 	*m_DlgSpell;
+				
+		void _showMisspelledWord();
+		void _suggestChange();
+		void _toggleChangeButtons(UT_Bool shouldShow);
+		void _change();
+		void _tryAgain();
+		void _changeAll();
+		
+		rgb_color normalText, badText;
+		sem_id modalSem;
 };
 
 SpellWin::SpellWin(BMessage *data) 
-	  :BWindow(data) {
-	spin = 1;
+	  :BWindow(data)
+{
+
 } 
 
-void SpellWin::SetDlg(AP_BeOSDialog_Spell *dlg) {
+void SpellWin::SetDlg(AP_BeOSDialog_Spell *dlg)
+{
         m_DlgSpell = dlg;
 
+	// As nice as using InterfaceElements is, the app doesn't properly set up
+	// the textRect for our BTextView..
+	BTextView* sentenceView = (BTextView *)FindView("sentencedisplay");
+	BRect frameRect = sentenceView->Bounds();
+	frameRect.InsetBy(5,5);
+	
+	sentenceView->SetTextRect(frameRect);
+		
+	normalText.red = normalText.blue = normalText.green = 0;
+	normalText.alpha = 255;
+
+	badText.red = 255;
+	badText.blue = badText.green = 0;
+	badText.alpha = 255;
+	
+	UT_Bool bRes = m_DlgSpell->nextMisspelledWord();
+	if(!bRes)
+		return;
+		
+	// set initial state
+	m_DlgSpell->makeWordVisible();
+	
+	_showMisspelledWord();
+	
+	// This semaphore ties up the window until after it deletes..
+	modalSem = create_sem(0,"SpellModalSem");
+
         Show();
-	while (spin) { snooze(1); }
-	Hide();
 
-#if 0
-   UT_Bool bRes = nextMisspelledWord();
-   while (bRes) {
- 	// show word in main window
-        makeWordVisible(); 
+	WaitForDelete(modalSem);
+}
+
+void SpellWin::_suggestChange()
+{
+	BListView* suggestList = (BListView *)FindView("suggestlist");
+	BTextControl* changeText = (BTextControl *)FindView("changetxt");
+	
+	m_DlgSpell->m_iSelectedRow = suggestList->CurrentSelection();
+	
+	if (!m_DlgSpell->m_Suggestions.count) 
+	{
+		// no change to suggest, ignore it
+		if (m_DlgSpell->m_iSelectedRow != -1)
+			suggestList->Select(-1);
+	}
+	else
+	{
+		// copy suggestion to edit field
+		UT_ASSERT((m_DlgSpell->m_iSelectedRow > -1));
+
+		BStringItem* selectedItem = (BStringItem *)suggestList->ItemAt(m_DlgSpell->m_iSelectedRow);
+		changeText->SetText(selectedItem->Text());
+	}
+
+}
+
+void SpellWin::_change(void)
+{
+	UT_UCSChar * replace = NULL;
+	BTextControl* changeText = (BTextControl *)FindView("changetxt");
+
+	if (m_DlgSpell->m_iSelectedRow != -1)
+	{
+		replace = m_DlgSpell->m_Suggestions.word[m_DlgSpell->m_iSelectedRow];
+		m_DlgSpell->changeWordWith(replace);
+	}
+	else
+	{
+		UT_UCS_cloneString_char(&replace, changeText->Text());
+		if (!UT_UCS_strlen(replace)) 
+		{
+			return;
+		}
+		m_DlgSpell->changeWordWith(replace);
+	}
+
+	_tryAgain();
+}
+
+
+void SpellWin::_tryAgain(void)
+{
+	BListView* suggestList = (BListView *)FindView("suggestlist");
+
+	// clear prior suggestions
+	m_DlgSpell->_purgeSuggestions();
+	
+	int32 numItems = suggestList->CountItems();
+	
+	// Clear out the dialog
+	for ( int32 i = 0; i < numItems; i++ )
+	{
+		BListItem* pItem = suggestList->RemoveItem((long int)0);
+		delete pItem;
+	}
+
+	// what's next
+	UT_Bool bRes = m_DlgSpell->nextMisspelledWord();
 
-	// update dialog with new misspelled word info/suggestions
-        //_showMisspelledWord();
+	if (bRes)
+	{
+		// show word in main window
+		m_DlgSpell->makeWordVisible();
 
-        // run into the GTK event loop for this window
-        //gtk_main();
+		// update dialog with new misspelled word info/suggestions
+		_showMisspelledWord();
+	}
+	else
+	{
+		PostMessage(B_QUIT_REQUESTED);
+	}
+}
 
-        //_purgeSuggestions();
+void SpellWin::_changeAll(void)
+{
+	BTextControl* changeText = (BTextControl *)FindView("changetxt");
+	UT_UCSChar * replace = NULL;
+	
+	if (m_DlgSpell->m_iSelectedRow != -1)
+	{
+		replace = (UT_UCSChar*) m_DlgSpell->m_Suggestions.word[m_DlgSpell->m_iSelectedRow];
+		m_DlgSpell->addChangeAll(replace);
+		m_DlgSpell->changeWordWith(replace);
+	}
+	else
+	{
+		UT_UCS_cloneString_char(&replace,changeText->Text());
+		if (!UT_UCS_strlen(replace)) 
+		{
+			return;
+		}
+			
+		m_DlgSpell->addChangeAll(replace);
+		m_DlgSpell->changeWordWith(replace);
+	}
+
+	_tryAgain();
+}
 
-        if (m_bCancelled) break;
+void SpellWin::_showMisspelledWord(void)
+{
+	UT_UCSChar *p;
+	UT_uint32 len;
+	char * buf;
+	UT_uint32 sum = 0;
+
+	BTextView* sentenceView = (BTextView *)FindView("sentencedisplay");
+	BListView* suggestList = (BListView *)FindView("suggestlist");
+	
+	sentenceView->SetText("");
+	sentenceView->MakeEditable(true);
+
+	// Run array is 3 long because begin sentence black, misspelled word red, end sentence black..
+	// Note: We need to delete this when we are done..
+	text_run_array* array = (text_run_array *)malloc(sizeof(text_run_array) + sizeof(text_run) * 3);
+	array->count = 3;
+
+	array->runs[0].offset = 0;
+	array->runs[0].font = be_plain_font;
+	array->runs[0].color = normalText;
+	
+	array->runs[1].font = be_bold_font;
+	array->runs[1].color = badText;
+
+	array->runs[2].font = be_plain_font;
+	array->runs[2].color = normalText;
+
+	// insert start of sentence
+
+	p = m_DlgSpell->_getPreWord();
+	len = UT_UCS_strlen(p);
+	if (len)
+	{
+		buf = new char [len + 1];
+		UT_UCS_strcpy_to_char(buf, p);
+		sentenceView->Insert(buf, (long int)len);
+		DELETEP(buf);
+	}
+	FREEP(p);
+	sum += len;
+
+	array->runs[1].offset = sum;
+	
+	p = m_DlgSpell->_getCurrentWord();
+	len = UT_UCS_strlen(p);
+	if (len)
+	{
+		buf = new char [len + 1];
+		UT_UCS_strcpy_to_char(buf, p);
+		sentenceView->Insert(sum, buf, (long int)len);
+		DELETEP(buf);
+	}
+	FREEP(p);
+	sum += len;
+
+	array->runs[2].offset = sum;
+
+	p = m_DlgSpell->_getPostWord();
+	len = UT_UCS_strlen(p);
+	if (len)
+	{
+		buf = new char [len + 1];
+		UT_UCS_strcpy_to_char(buf, p);
+		sentenceView->Insert(sum, buf, (long int)len);
+		DELETEP(buf);
+	}
+	FREEP(p);
+	
+	sentenceView->SetRunArray(0, (long int)sum + len , array);
+	sentenceView->MakeEditable(false);
+
+	// insert suggestions
+	if (!m_DlgSpell->m_Suggestions.count) 
+	{
+		const XAP_StringSet * pSS = m_DlgSpell->m_pApp->getStringSet();
+		BStringItem* emptyItem = new BStringItem(pSS->getValue(AP_STRING_ID_DLG_Spell_NoSuggestions));
+		suggestList->AddItem(emptyItem);
+		m_DlgSpell->m_iSelectedRow = -1;
+		_toggleChangeButtons(UT_FALSE);
+	} 
+	else 
+	{
+		for (int i = 0; i < m_DlgSpell->m_Suggestions.count; i++)
+		{
+			p = (UT_UCSChar *) m_DlgSpell->m_Suggestions.word[i];
+			len = UT_UCS_strlen(p);
+			if (len)
+			{
+				buf = new char [len + 1];
+				UT_UCS_strcpy_to_char(buf, p);
+				BStringItem* pItem = new BStringItem(buf);
+				suggestList->AddItem(pItem);
+				DELETEP(buf);
+			}
+		}
+
+		m_DlgSpell->m_iSelectedRow = 0;
+		_toggleChangeButtons(UT_TRUE);
+	}
 
-        // get the next unknown word
-        bRes = nextMisspelledWord();                      
-   }
-#endif
+	suggestList->Select(0);
+	_suggestChange();
 }
 
-void SpellWin::DispatchMessage(BMessage *msg, BHandler *handler) {
-	switch(msg->what) {
+void SpellWin::DispatchMessage(BMessage *msg, BHandler *handler) 
+{
+	BTextControl* editSuggest;
+	BListView* suggestList;
+	int32 selIndex;
+	BStringItem* pCurSelItem;
+	
+	switch(msg->what) 
+	{
+	case 'ibut': // ignore button
+		m_DlgSpell->ignoreWord();
+		_tryAgain();
+		break;
+	
+	case 'iabu': // ignore all button.
+		m_DlgSpell->addIgnoreAll();
+		m_DlgSpell->ignoreWord();
+		_tryAgain();
+		break;
+		
+	case 'abut': // add button
+		m_DlgSpell->addToDict();
+		m_DlgSpell->ignoreWord();
+		_tryAgain();
+		break;
+		
+	case 'cbut':
+		_change();
+		break;
+		
+	case 'cabu':
+		_changeAll();
+		break;
+	
+	case 'selc':
+		// Update the current selection in the add box..
+		suggestList = (BListView *)FindView("suggestlist");
+		editSuggest = (BTextControl *)FindView("changetxt");
+	
+		m_DlgSpell->m_iSelectedRow = suggestList->CurrentSelection();
+		selIndex = m_DlgSpell->m_iSelectedRow;
+		
+		pCurSelItem = (BStringItem *)suggestList->ItemAt(m_DlgSpell->m_iSelectedRow);
+	
+		if(pCurSelItem)
+			editSuggest->TextView()->SetText(pCurSelItem->Text());
+
+		break;
+		
+	case 'invs': // Called when the user double-clicks a suggested word in the spell dialog.
+		suggestList = (BListView *)FindView("suggestlist");
+		if( msg->FindInt32("index" , &selIndex) == B_OK)
+		{
+			m_DlgSpell->m_iSelectedRow = selIndex;
+			_change();
+		}
+		break;
+	
+	case 'spmo': // Whenever the user edits the text control.
+
+		// Determine if the user clicked an item in the suggest box.
+		
+		suggestList = (BListView *)FindView("suggestlist");
+		editSuggest = (BTextControl *)FindView("changetxt");
+
+		for(int i = 0; i < suggestList->CountItems(); i ++)
+		{
+			pCurSelItem = (BStringItem *)suggestList->ItemAt(i);
+
+			if(strcmp(pCurSelItem->Text() , editSuggest->Text()) == 0)
+			{
+				return;;
+			}
+		}
+		
+		// The user is editing it so, enable the change button.
+		_toggleChangeButtons(UT_TRUE);
+		
+		suggestList->DeselectAll();
+		m_DlgSpell->m_iSelectedRow = -1;
+		
+		break;
+		
         default:
                 BWindow::DispatchMessage(msg, handler);
         }
+	
 } 
 
 //Behave like a good citizen
-bool SpellWin::QuitRequested() {
-	spin = 0;
+bool SpellWin::QuitRequested()
+{
+	delete_sem(modalSem);
         return(true);
 }
 
+void SpellWin::_toggleChangeButtons(UT_Bool shouldShow)
+{
+	BButton *change, *changeall;
+	change = (BButton *)FindView("change");
+	changeall = (BButton *)FindView("changeall");
+	
+	if(change)
+		change->SetEnabled(shouldShow);
+	if(changeall)
+		changeall->SetEnabled(shouldShow);
+}
 
 /*****************************************************************/
 
@@ -125,7 +482,7 @@
                 newwin = new SpellWin(&msg);
                 newwin->SetDlg(this);
                 //Take the information here ...
-                newwin->Close();
+                // newwin->Close(); QuitRequested kills this dialog..
         }                
 }
 
--- /windisk/abiword/abi/src/wp/ap/beos/ap_BeOSDialog_Spell.h	Wed Jul 26 13:20:10 2000
+++ ap_BeOSDialog_Spell.h	Mon Jul 24 15:39:39 2000
@@ -28,6 +28,8 @@
 
 class AP_BeOSDialog_Spell: public AP_Dialog_Spell
 {
+	friend class SpellWin;
+	
  public:
    AP_BeOSDialog_Spell(XAP_DialogFactory * pDlgFactory, XAP_Dialog_Id id);
    virtual ~AP_BeOSDialog_Spell(void);
This archive was generated by hypermail 2b25 : Tue Jul 25 2000 - 10:33:32 CDT