<commit_before>#include <eeros/sequencer/Sequence.hpp>
#include <eeros/sequencer/Sequencer.hpp>
#include <eeros/sequencer/SequenceException.hpp>
#include <eeros/sequencer/ErrorHandler.hpp>

using namespace eeros::sequencer;

std::list<eeros::sequencer::Sequence*> Sequence::allSequences;

Sequence::Sequence(std::string name, Sequencer& caller)
	: sequenceName(name),
      callerThread(caller),
	  state(kSequenceNotStarted) {
	if(&callerThread != Sequencer::getMainSequencer()){
		Sequencer::getMainSequencer()->addSubSequencer(&caller);
	}
	Sequence* seq = getSequence(name);
	if(seq){
		 throw "Sequence allready exists!";
	}
	Sequence::allSequences.push_back(this);
	currentCallBackIterator = callBacks.end();
}

std::string Sequence::getName(){
	return sequenceName;
}

void Sequence::addCallBack(eeros::sequencer::Sequence::method callback){
	callBacks.push_back(callback);
}

std::list<Sequence::method>::iterator Sequence::findCallBack(method callback, bool setCurrent) {
	std::list<Sequence::method>::iterator iter = callBacks.begin();
	while(iter != callBacks.end()){
		if(*iter == callback){
			if(setCurrent){
				currentCallBackIterator = iter;
			}
			return iter;
		}
		iter++;
	}
	throw "no Method found!";
	return iter;
}

void Sequence::setCurrentCallBack(std::list<eeros::sequencer::Sequence::method>::iterator iter){
	currentCallBackIterator = iter;
}

void Sequence::run(){
	try{
		if(callBacks.empty()){
			fillCallBacks();
		}
		//std::list<Sequence::method>::iterator iter = callBacks.begin();
		if(currentCallBackIterator == callBacks.end()){
			currentCallBackIterator = callBacks.begin();
			state = kSequenceRunning;

		}
		method fun;
		while(currentCallBackIterator != callBacks.end()){
			fun = *currentCallBackIterator;
			(this->*fun)();
			currentCallBackIterator++;
		}
		state = kSequenceFinished;
	}catch(SequenceException* e){
		//ErrorHandling
		try{
			if(e->errorHandler){
				if(e->returnToBegin){
					currentCallBackIterator = callBacks.begin();
				}else if (e->goToNext){
					findCallBack(e->nextMethod, true);
				}
				//else continue after Error Handling with the same Method
				e->errorHandler->run();
			}
		}catch(...){
			callerThread.stop();
		}
	}
}

Sequence* Sequence::getSequence(std::string name){
	std::list<Sequence*>::iterator iter = eeros::sequencer::Sequence::allSequences.begin();
		while(iter != eeros::sequencer::Sequence::allSequences.end()){
			if((*iter)->getName().compare(name) == 0){
				return *iter;
			}
			iter++;
		}
		return 0;
}

int Sequence::getState(){
	return state;
}<commit_msg>Delete the sequence in the list of allSequences in the destructor, because the list is static!<commit_after>#include <eeros/sequencer/Sequence.hpp>
#include <eeros/sequencer/Sequencer.hpp>
#include <eeros/sequencer/SequenceException.hpp>
#include <eeros/sequencer/ErrorHandler.hpp>

using namespace eeros::sequencer;

std::list<eeros::sequencer::Sequence*> Sequence::allSequences;

Sequence::Sequence(std::string name, Sequencer& caller)
	: sequenceName(name),
      callerThread(caller),
	  state(kSequenceNotStarted) {
	if(&callerThread != Sequencer::getMainSequencer()){
		Sequencer::getMainSequencer()->addSubSequencer(&caller);
	}
	Sequence* seq = getSequence(sequenceName);
	if(seq){
		 throw "Sequence allready exists!";
	}
	Sequence::allSequences.push_back(this);
	currentCallBackIterator = callBacks.end();
}

Sequence::~Sequence(){
	removeSequence(sequenceName);
}

std::string Sequence::getName(){
	return sequenceName;
}

void Sequence::addCallBack(eeros::sequencer::Sequence::method callback){
	callBacks.push_back(callback);
}

std::list<Sequence::method>::iterator Sequence::findCallBack(method callback, bool setCurrent) {
	std::list<Sequence::method>::iterator iter = callBacks.begin();
	while(iter != callBacks.end()){
		if(*iter == callback){
			if(setCurrent){
				currentCallBackIterator = iter;
			}
			return iter;
		}
		iter++;
	}
	throw "no Method found!";
	return iter;
}

void Sequence::setCurrentCallBack(std::list<eeros::sequencer::Sequence::method>::iterator iter){
	currentCallBackIterator = iter;
}

void Sequence::run(){
	try{
		if(callBacks.empty()){
			fillCallBacks();
		}
		//std::list<Sequence::method>::iterator iter = callBacks.begin();
		if(currentCallBackIterator == callBacks.end()){
			currentCallBackIterator = callBacks.begin();
			state = kSequenceRunning;

		}
		method fun;
		while(currentCallBackIterator != callBacks.end()){
			fun = *currentCallBackIterator;
			(this->*fun)();
			currentCallBackIterator++;
		}
		state = kSequenceFinished;
	}catch(SequenceException* e){
		//ErrorHandling
		try{
			if(e->errorHandler){
				if(e->returnToBegin){
					currentCallBackIterator = callBacks.begin();
				}else if (e->goToNext){
					findCallBack(e->nextMethod, true);
				}
				//else continue after Error Handling with the same Method
				e->errorHandler->run();
			}
		}catch(...){
			callerThread.stop();
		}
	}
}

Sequence* Sequence::getSequence(std::string name){
	std::list<Sequence*>::iterator iter = eeros::sequencer::Sequence::allSequences.begin();
		while(iter != eeros::sequencer::Sequence::allSequences.end()){
			if((*iter)->getName().compare(name) == 0){
				return *iter;
			}
			iter++;
		}
		return 0;
}

void Sequence::removeSequence(std::string name){
	std::list<Sequence*>::iterator iter = eeros::sequencer::Sequence::allSequences.begin();
	while(iter != eeros::sequencer::Sequence::allSequences.end()){
		if((*iter)->getName().compare(name) == 0){
			iter = allSequences.erase(iter);
		}else{
		  iter++;
		}
	}
}

int Sequence::getState(){
	return state;
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: hf_docentry.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-12 15:32:39 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef ADC_DISPLAY_HF_DOCENTRY_HXX
#define ADC_DISPLAY_HF_DOCENTRY_HXX

// USED SERVICES
    // BASE CLASSES
#include "htmlfactory.hxx"
    // COMPONENTS
    // PARAMETERS

/** @resp
    Produces a list of
..
 and
.
*/
class HF_DocEntryList : public HtmlMaker
{
  public:

                        HF_DocEntryList(
                            Xml::Element &      o_rOut );
    virtual             ~HF_DocEntryList();

    Xml::Element &      Produce_Term(
                            const char *        i_sTerm = 0 );
    Xml::Element &      Produce_NormalTerm(     /// Font will not be bold.
                            const char *        i_sTerm = 0 );
    Xml::Element &      Produce_Definition();
};

#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.2.24); FILE MERGED 2005/09/05 13:11:15 rt 1.2.24.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: hf_docentry.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 17:55:01 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef ADC_DISPLAY_HF_DOCENTRY_HXX
#define ADC_DISPLAY_HF_DOCENTRY_HXX

// USED SERVICES
    // BASE CLASSES
#include "htmlfactory.hxx"
    // COMPONENTS
    // PARAMETERS

/** @resp
    Produces a list of
..
 and
.
*/
class HF_DocEntryList : public HtmlMaker
{
  public:

                        HF_DocEntryList(
                            Xml::Element &      o_rOut );
    virtual             ~HF_DocEntryList();

    Xml::Element &      Produce_Term(
                            const char *        i_sTerm = 0 );
    Xml::Element &      Produce_NormalTerm(     /// Font will not be bold.
                            const char *        i_sTerm = 0 );
    Xml::Element &      Produce_Definition();
};

#endif
<|endoftext|>


<commit_before>/* This file is part of the KDE project
   Copyright (C) 2010 Thomas Fjellstrom <thomas@fjellstrom.ca>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

//BEGIN Includes
#include "katefiletree.h"
#include "katefiletree.moc"
#include "katefiletreemodel.h"
#include "katefiletreeproxymodel.h"
#include "katefiletreedebug.h"

#include <ktexteditor/document.h>
#include <kate/application.h>
#include <kate/app/katesavemodifieddialog.h>
#include <kate/app/katedocmanager.h>
#include <kate/documentmanager.h>
#include <KLocale>

#include <QtGui/QMenu>
#include <QtGui/QContextMenuEvent>
#include <kicon.h>
#include <kdebug.h>
//END Includes

//BEGIN KateFileTree

KateFileTree::KateFileTree(QWidget *parent): QTreeView(parent)
{
  setAcceptDrops(false);
  setIndentation(12);
  setAllColumnsShowFocus(true);

  setTextElideMode(Qt::ElideLeft);

  connect( this, SIGNAL(pressed(const QModelIndex &)), this, SLOT(mousePressed(const QModelIndex &)));
  connect( this, SIGNAL(clicked(const QModelIndex &)), this, SLOT(mouseClicked(const QModelIndex &)));

  m_filelistCloseDocument = new QAction( KIcon("window-close"), i18n( "Close" ), this );
  connect( m_filelistCloseDocument, SIGNAL( triggered() ), this, SLOT( slotDocumentClose() ) );
  m_filelistCloseDocument->setWhatsThis(i18n("Close the current document."));

  QActionGroup *modeGroup = new QActionGroup(this);

  m_treeModeAction = setupOption(modeGroup, KIcon("view-list-tree"), i18n("Tree Mode"),
                                 i18n("Set view style to Tree Mode"),
                                 SLOT( slotTreeMode() ), true);

  m_listModeAction = setupOption(modeGroup, KIcon("view-list-text"), i18n("List Mode"),
                                 i18n("Set view style to List Mode"),
                                 SLOT( slotListMode() ), false);

  QActionGroup *sortGroup = new QActionGroup(this);

  m_sortByFile = setupOption(sortGroup, KIcon(), i18n("Document Name"),
                             i18n("Sort by Document Name"),
                             SLOT( slotSortName() ), true);

  m_sortByPath = setupOption(sortGroup, KIcon(), i18n("Document Path"),
                             i18n("Sort by Document Path"),
                             SLOT( slotSortPath() ), false);

  m_sortByOpeningOrder =  setupOption(sortGroup, KIcon(), i18n("Opening Order"),
                             i18n("Sort by Opening Order"),
                             SLOT( slotSortOpeningOrder() ), false);

  QPalette p = palette();
  p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight));
  p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText));
  setPalette(p);
}

KateFileTree::~KateFileTree()
{}

QAction *KateFileTree::setupOption(
  QActionGroup *group,
  const KIcon &icon,
  const QString &label,
  const QString &whatsThis,
  const char *slot,
  bool checked
)
{
  QAction *new_action = new QAction( icon, label, this );
  new_action->setWhatsThis(whatsThis);
  new_action->setActionGroup(group);
  new_action->setCheckable(true);
  new_action->setChecked(checked);
  connect( new_action, SIGNAL( triggered() ), this, slot );
  return new_action;
}

void KateFileTree::slotListMode()
{
  emit viewModeChanged(true);
}

void KateFileTree::slotTreeMode()
{
  emit viewModeChanged(false);
}

void KateFileTree::slotSortName()
{
  emit sortRoleChanged(Qt::DisplayRole);
}

void KateFileTree::slotSortPath()
{
  emit sortRoleChanged(KateFileTreeModel::PathRole);
}

void KateFileTree::slotSortOpeningOrder()
{
  emit sortRoleChanged(KateFileTreeModel::OpeningOrderRole);
}

void KateFileTree::slotCurrentChanged ( const QModelIndex &current, const QModelIndex &previous )
{
  kDebug(debugArea()) << "current:" << current << "previous:" << previous;

  if(!current.isValid())
    return;

  KTextEditor::Document *doc = model()->data(current, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
  if(doc) {
    kDebug(debugArea()) << "got doc, setting prev:" << current;
    m_previouslySelected = current;
  }
}

void KateFileTree::mousePressed ( const QModelIndex &index )
{
  kDebug(debugArea()) << "got index" << index;

  KTextEditor::Document *doc = model()->data(index, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
  if(doc) {
    kDebug(debugArea()) << "got doc, setting prev:" << index;
    m_previouslySelected = index;
  }
}

void KateFileTree::mouseClicked ( const QModelIndex &index )
{
  kDebug(debugArea()) << "got index" << index;

  KTextEditor::Document *doc = model()->data(index, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
  if(doc) {
    kDebug(debugArea()) << "got doc" << index << "setting prev:" << QModelIndex();
    emit activateDocument(doc);
    //m_previouslySelected = QModelIndex();
  }
  else {
    kDebug(debugArea()) << "selecting previous item" << m_previouslySelected;

    selectionModel()->setCurrentIndex(m_previouslySelected,QItemSelectionModel::ClearAndSelect);
  }

}

void KateFileTree::contextMenuEvent ( QContextMenuEvent * event ) {
  m_indexContextMenu=selectionModel()->currentIndex();

  if (m_previouslySelected.isValid()) {
    selectionModel()->setCurrentIndex(m_previouslySelected,QItemSelectionModel::ClearAndSelect);
  }

  KateFileTreeProxyModel *ftpm = static_cast<KateFileTreeProxyModel*>(model());
  KateFileTreeModel *ftm = static_cast<KateFileTreeModel*>(ftpm->sourceModel());

  bool listMode = ftm->listMode();
  m_treeModeAction->setChecked(!listMode);
  m_listModeAction->setChecked(listMode);

  int sortRole = ftpm->sortRole();
  m_sortByFile->setChecked(sortRole == Qt::DisplayRole);
  m_sortByPath->setChecked(sortRole == KateFileTreeModel::PathRole);
  m_sortByOpeningOrder->setChecked(sortRole == KateFileTreeModel::OpeningOrderRole);

  QMenu menu;
  menu.addAction(m_filelistCloseDocument);
  menu.addSeparator();
  QMenu *view_menu = menu.addMenu(i18n("View Mode"));
  view_menu->addAction(m_treeModeAction);
  view_menu->addAction(m_listModeAction);

  QMenu *sort_menu = menu.addMenu(i18n("Sort By"));
  sort_menu->addAction(m_sortByFile);
  sort_menu->addAction(m_sortByPath);
  sort_menu->addAction(m_sortByOpeningOrder);

  menu.exec(viewport()->mapToGlobal(event->pos()));

  event->accept();
}

Q_DECLARE_METATYPE(QList<KTextEditor::Document*>);

void KateFileTree::slotDocumentClose() {
  m_previouslySelected = QModelIndex();
  QVariant v = m_indexContextMenu.data(KateFileTreeModel::DocumentTreeRole);
  if (!v.isValid()) return;
  QList<KTextEditor::Document*> closingDocuments = v.value<QList<KTextEditor::Document*> >();
  QList<KTextEditor::Document*> modifiedDocuments = KateDocManager::self()->modifiedDocumentList();
  QList<KTextEditor::Document*> closingModifiedDocuments;
  // This shouldn't be a bottleneck, so use simple intersection algorithm
  foreach(KTextEditor::Document* document, modifiedDocuments) {
    if (closingDocuments.contains(document)) {
      closingModifiedDocuments.append(document);
    }
  }
  bool doClose = KateSaveModifiedDialog::queryClose(this, closingModifiedDocuments);
  if (doClose) {
    Kate::DocumentManager* documentManager = Kate::application()->documentManager();
    foreach(KTextEditor::Document* document, closingDocuments) {
      documentManager->closeDocument(document, false);
    }
  }
}

void KateFileTree::slotDocumentPrev()
{
  kDebug(debugArea()) << "BEGIN";
  KateFileTreeProxyModel *ftpm = static_cast<KateFileTreeProxyModel*>(model());

  QModelIndex current_index = currentIndex();
  QModelIndex prev;

  // scan up the tree skipping any dir nodes

  //kDebug(debugArea()) << "cur" << ftpm->data(current_index, Qt::DisplayRole);
  while(current_index.isValid()) {
    if(current_index.row() > 0) {
      current_index = ftpm->sibling(current_index.row()-1, current_index.column(), current_index);
      //kDebug(debugArea()) << "get prev" << ftpm->data(current_index, Qt::DisplayRole);
      if(!current_index.isValid()) {
        //kDebug(debugArea()) << "somehow getting prev index from sibling didn't work :(";
        break;
      }

      if(ftpm->isDir(current_index)) {
        // try and select the last child in this parent
        //kDebug(debugArea()) << "is a dir";
        int children = ftpm->rowCount(current_index);
        current_index = ftpm->index(children-1, 0, current_index);
        //kDebug(debugArea()) << "child" << ftpm->data(current_index, Qt::DisplayRole);
        if(ftpm->isDir(current_index)) {
          // since we're a dir, keep going
          //kDebug(debugArea()) << "child is a dir";
          while(ftpm->isDir(current_index)) {
            children = ftpm->rowCount(current_index);
            current_index = ftpm->index(children-1, 0, current_index);
          }

          if(!ftpm->isDir(current_index)) {
            prev = current_index;
            break;
          }

          continue;
        } else {
          // we're the previous file, set prev
          //kDebug(debugArea()) << "got doc 1";
          prev = current_index;
          break;
        }
      } else { // found document item
        //kDebug(debugArea()) << "got doc 2";
        prev = current_index;
        break;
      }
    }
    else {
      //kDebug(debugArea()) << "get parent";
      // just select the parent, the logic above will handle the rest
      current_index = ftpm->parent(current_index);
      //kDebug(debugArea()) << "got parent" << ftpm->data(current_index, Qt::DisplayRole);
      if(!current_index.isValid()) {
        // past the root node here, try and wrap arround
        //kDebug(debugArea()) << "parent invalid";

        int children = ftpm->rowCount(current_index);
        QModelIndex last_index = ftpm->index(children-1, 0, current_index);
        //kDebug(debugArea()) << "last" << ftpm->data(last_index, Qt::DisplayRole);
        if(!last_index.isValid())
          break;

        if(ftpm->isDir(last_index)) {
          // last node is a dir, select last child row
          //kDebug(debugArea()) << "last root is a dir, select child";
          int last_children = ftpm->rowCount(last_index);
          prev = ftpm->index(last_children-1, 0, last_index);
          //kDebug(debugArea()) << "last child" << ftpm->data(current_index, Qt::DisplayRole);
          // bug here?
          break;
        }
        else {
          // got last file node
          //kDebug(debugArea()) << "got doc";
          prev = last_index;
          break;
        }
      }
    }
  }

  if(prev.isValid()) {
    //kDebug(debugArea()) << "got prev node:" << prev;
    //kDebug(debugArea()) << "doc:" << ftpm->data(prev, Qt::DisplayRole).value<QString>();

    KTextEditor::Document *doc = model()->data(prev, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
    emit activateDocument(doc);
  }
  else {
    kDebug(debugArea()) << "didn't get prev node :(";
  }

  kDebug(debugArea()) << "END";
}

/*
plan:

default: select next sibling
if cur is a dir, select it

*/

void KateFileTree::slotDocumentNext()
{
  kDebug(debugArea()) << "BEGIN";

  KateFileTreeProxyModel *ftpm = static_cast<KateFileTreeProxyModel*>(model());

  QModelIndex current_index = currentIndex();
  int parent_row_count = ftpm->rowCount( ftpm->parent(current_index) );
  QModelIndex next;

  // scan down the tree skipping any dir nodes
  while(current_index.isValid()) {
    if(current_index.row() < parent_row_count-1) {
      current_index = ftpm->sibling(current_index.row()+1, current_index.column(), current_index);
      if(!current_index.isValid()) {
        break;
      }

      if(ftpm->isDir(current_index)) {
        // we have a dir node
        while(ftpm->isDir(current_index)) {
          current_index = ftpm->index(0, 0, current_index);
        }

        parent_row_count = ftpm->rowCount( ftpm->parent(current_index) );

        if(!ftpm->isDir(current_index)) {
          next = current_index;
          break;
        }
      } else { // found document item
        next = current_index;
        break;
      }
    }
    else {
      // select the parent's next sibling
      QModelIndex parent_index = ftpm->parent(current_index);
      int grandparent_row_count = ftpm->rowCount( ftpm->parent(parent_index) );

      current_index = parent_index;
      parent_row_count = grandparent_row_count;

      // at least if we're not past the last node
      if(!current_index.isValid()) {
        // past the root node here, try and wrap arround
        QModelIndex last_index = ftpm->index(0, 0, QModelIndex());
        if(!last_index.isValid()) {
          break;
        }

        if(ftpm->isDir(last_index)) {
          // last node is a dir, select first child row
          while(ftpm->isDir(last_index)) {
            if(ftpm->rowCount(last_index)) {
              // has children, select first
              last_index = ftpm->index(0, 0, last_index);
            }
          }

          next = last_index;
          break;
        }
        else {
          // got first file node
          next = last_index;
          break;
        }
      }
    }
  }

  if(next.isValid()) {
    //kDebug(debugArea()) << "got next node:" << next;
    //kDebug(debugArea()) << "doc:" << ftpm->data(next, Qt::DisplayRole).value<QString>();

    KTextEditor::Document *doc = model()->data(next, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
    emit activateDocument(doc);
  }
  else {
    kDebug(debugArea()) << "didn't get next node :(";
  }

  kDebug(debugArea()) << "END";
}
//END KateFileTree

// kate: space-indent on; indent-width 2; replace-tabs on;
<commit_msg>FileTree: allow directories to be highlighted when calling a context menu; call SaveModifiedDialog only when there are modified documents.<commit_after>/* This file is part of the KDE project
   Copyright (C) 2010 Thomas Fjellstrom <thomas@fjellstrom.ca>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

//BEGIN Includes
#include "katefiletree.h"
#include "katefiletree.moc"
#include "katefiletreemodel.h"
#include "katefiletreeproxymodel.h"
#include "katefiletreedebug.h"

#include <ktexteditor/document.h>
#include <kate/application.h>
#include <kate/app/katesavemodifieddialog.h>
#include <kate/app/katedocmanager.h>
#include <kate/documentmanager.h>
#include <KLocale>

#include <QtGui/QMenu>
#include <QtGui/QContextMenuEvent>
#include <kicon.h>
#include <kdebug.h>
//END Includes

//BEGIN KateFileTree

KateFileTree::KateFileTree(QWidget *parent): QTreeView(parent)
{
  setAcceptDrops(false);
  setIndentation(12);
  setAllColumnsShowFocus(true);

  setTextElideMode(Qt::ElideLeft);

  connect( this, SIGNAL(pressed(const QModelIndex &)), this, SLOT(mousePressed(const QModelIndex &)));
  connect( this, SIGNAL(clicked(const QModelIndex &)), this, SLOT(mouseClicked(const QModelIndex &)));

  m_filelistCloseDocument = new QAction( KIcon("window-close"), i18n( "Close" ), this );
  connect( m_filelistCloseDocument, SIGNAL( triggered() ), this, SLOT( slotDocumentClose() ) );
  m_filelistCloseDocument->setWhatsThis(i18n("Close the current document."));

  QActionGroup *modeGroup = new QActionGroup(this);

  m_treeModeAction = setupOption(modeGroup, KIcon("view-list-tree"), i18n("Tree Mode"),
                                 i18n("Set view style to Tree Mode"),
                                 SLOT( slotTreeMode() ), true);

  m_listModeAction = setupOption(modeGroup, KIcon("view-list-text"), i18n("List Mode"),
                                 i18n("Set view style to List Mode"),
                                 SLOT( slotListMode() ), false);

  QActionGroup *sortGroup = new QActionGroup(this);

  m_sortByFile = setupOption(sortGroup, KIcon(), i18n("Document Name"),
                             i18n("Sort by Document Name"),
                             SLOT( slotSortName() ), true);

  m_sortByPath = setupOption(sortGroup, KIcon(), i18n("Document Path"),
                             i18n("Sort by Document Path"),
                             SLOT( slotSortPath() ), false);

  m_sortByOpeningOrder =  setupOption(sortGroup, KIcon(), i18n("Opening Order"),
                             i18n("Sort by Opening Order"),
                             SLOT( slotSortOpeningOrder() ), false);

  QPalette p = palette();
  p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight));
  p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText));
  setPalette(p);
}

KateFileTree::~KateFileTree()
{}

QAction *KateFileTree::setupOption(
  QActionGroup *group,
  const KIcon &icon,
  const QString &label,
  const QString &whatsThis,
  const char *slot,
  bool checked
)
{
  QAction *new_action = new QAction( icon, label, this );
  new_action->setWhatsThis(whatsThis);
  new_action->setActionGroup(group);
  new_action->setCheckable(true);
  new_action->setChecked(checked);
  connect( new_action, SIGNAL( triggered() ), this, slot );
  return new_action;
}

void KateFileTree::slotListMode()
{
  emit viewModeChanged(true);
}

void KateFileTree::slotTreeMode()
{
  emit viewModeChanged(false);
}

void KateFileTree::slotSortName()
{
  emit sortRoleChanged(Qt::DisplayRole);
}

void KateFileTree::slotSortPath()
{
  emit sortRoleChanged(KateFileTreeModel::PathRole);
}

void KateFileTree::slotSortOpeningOrder()
{
  emit sortRoleChanged(KateFileTreeModel::OpeningOrderRole);
}

void KateFileTree::slotCurrentChanged ( const QModelIndex &current, const QModelIndex &previous )
{
  kDebug(debugArea()) << "current:" << current << "previous:" << previous;

  if(!current.isValid())
    return;

  KTextEditor::Document *doc = model()->data(current, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
  if(doc) {
    kDebug(debugArea()) << "got doc, setting prev:" << current;
    m_previouslySelected = current;
  }
}

void KateFileTree::mousePressed ( const QModelIndex &index )
{
  kDebug(debugArea()) << "got index" << index;

  m_previouslySelected = index;
}

void KateFileTree::mouseClicked ( const QModelIndex &index )
{
  kDebug(debugArea()) << "got index" << index;

  KTextEditor::Document *doc = model()->data(index, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
  if(doc) {
    kDebug(debugArea()) << "got doc" << index << "setting prev:" << QModelIndex();
    emit activateDocument(doc);
    //m_previouslySelected = QModelIndex();
  }
  else {
    kDebug(debugArea()) << "selecting previous item" << m_previouslySelected;

    selectionModel()->setCurrentIndex(m_previouslySelected,QItemSelectionModel::ClearAndSelect);
  }

}

void KateFileTree::contextMenuEvent ( QContextMenuEvent * event ) {
  m_indexContextMenu=selectionModel()->currentIndex();

  if (m_previouslySelected.isValid()) {
    selectionModel()->setCurrentIndex(m_previouslySelected,QItemSelectionModel::ClearAndSelect);
  }

  KateFileTreeProxyModel *ftpm = static_cast<KateFileTreeProxyModel*>(model());
  KateFileTreeModel *ftm = static_cast<KateFileTreeModel*>(ftpm->sourceModel());

  bool listMode = ftm->listMode();
  m_treeModeAction->setChecked(!listMode);
  m_listModeAction->setChecked(listMode);

  int sortRole = ftpm->sortRole();
  m_sortByFile->setChecked(sortRole == Qt::DisplayRole);
  m_sortByPath->setChecked(sortRole == KateFileTreeModel::PathRole);
  m_sortByOpeningOrder->setChecked(sortRole == KateFileTreeModel::OpeningOrderRole);

  QMenu menu;
  menu.addAction(m_filelistCloseDocument);
  menu.addSeparator();
  QMenu *view_menu = menu.addMenu(i18n("View Mode"));
  view_menu->addAction(m_treeModeAction);
  view_menu->addAction(m_listModeAction);

  QMenu *sort_menu = menu.addMenu(i18n("Sort By"));
  sort_menu->addAction(m_sortByFile);
  sort_menu->addAction(m_sortByPath);
  sort_menu->addAction(m_sortByOpeningOrder);

  menu.exec(viewport()->mapToGlobal(event->pos()));

  event->accept();
}

Q_DECLARE_METATYPE(QList<KTextEditor::Document*>);

void KateFileTree::slotDocumentClose() {
  m_previouslySelected = QModelIndex();
  QVariant v = m_indexContextMenu.data(KateFileTreeModel::DocumentTreeRole);
  if (!v.isValid()) return;
  QList<KTextEditor::Document*> closingDocuments = v.value<QList<KTextEditor::Document*> >();
  QList<KTextEditor::Document*> modifiedDocuments = KateDocManager::self()->modifiedDocumentList();
  QList<KTextEditor::Document*> closingModifiedDocuments;
  // This shouldn't be a bottleneck, so use simple intersection algorithm
  foreach(KTextEditor::Document* document, modifiedDocuments) {
    if (closingDocuments.contains(document)) {
      closingModifiedDocuments.append(document);
    }
  }
  bool doClose = true;
  if (closingModifiedDocuments.size()) {
    doClose = KateSaveModifiedDialog::queryClose(this, closingModifiedDocuments);
  }
  if (doClose) {
    Kate::DocumentManager* documentManager = Kate::application()->documentManager();
    foreach(KTextEditor::Document* document, closingDocuments) {
      documentManager->closeDocument(document, false);
    }
  }
}

void KateFileTree::slotDocumentPrev()
{
  kDebug(debugArea()) << "BEGIN";
  KateFileTreeProxyModel *ftpm = static_cast<KateFileTreeProxyModel*>(model());

  QModelIndex current_index = currentIndex();
  QModelIndex prev;

  // scan up the tree skipping any dir nodes

  //kDebug(debugArea()) << "cur" << ftpm->data(current_index, Qt::DisplayRole);
  while(current_index.isValid()) {
    if(current_index.row() > 0) {
      current_index = ftpm->sibling(current_index.row()-1, current_index.column(), current_index);
      //kDebug(debugArea()) << "get prev" << ftpm->data(current_index, Qt::DisplayRole);
      if(!current_index.isValid()) {
        //kDebug(debugArea()) << "somehow getting prev index from sibling didn't work :(";
        break;
      }

      if(ftpm->isDir(current_index)) {
        // try and select the last child in this parent
        //kDebug(debugArea()) << "is a dir";
        int children = ftpm->rowCount(current_index);
        current_index = ftpm->index(children-1, 0, current_index);
        //kDebug(debugArea()) << "child" << ftpm->data(current_index, Qt::DisplayRole);
        if(ftpm->isDir(current_index)) {
          // since we're a dir, keep going
          //kDebug(debugArea()) << "child is a dir";
          while(ftpm->isDir(current_index)) {
            children = ftpm->rowCount(current_index);
            current_index = ftpm->index(children-1, 0, current_index);
          }

          if(!ftpm->isDir(current_index)) {
            prev = current_index;
            break;
          }

          continue;
        } else {
          // we're the previous file, set prev
          //kDebug(debugArea()) << "got doc 1";
          prev = current_index;
          break;
        }
      } else { // found document item
        //kDebug(debugArea()) << "got doc 2";
        prev = current_index;
        break;
      }
    }
    else {
      //kDebug(debugArea()) << "get parent";
      // just select the parent, the logic above will handle the rest
      current_index = ftpm->parent(current_index);
      //kDebug(debugArea()) << "got parent" << ftpm->data(current_index, Qt::DisplayRole);
      if(!current_index.isValid()) {
        // past the root node here, try and wrap arround
        //kDebug(debugArea()) << "parent invalid";

        int children = ftpm->rowCount(current_index);
        QModelIndex last_index = ftpm->index(children-1, 0, current_index);
        //kDebug(debugArea()) << "last" << ftpm->data(last_index, Qt::DisplayRole);
        if(!last_index.isValid())
          break;

        if(ftpm->isDir(last_index)) {
          // last node is a dir, select last child row
          //kDebug(debugArea()) << "last root is a dir, select child";
          int last_children = ftpm->rowCount(last_index);
          prev = ftpm->index(last_children-1, 0, last_index);
          //kDebug(debugArea()) << "last child" << ftpm->data(current_index, Qt::DisplayRole);
          // bug here?
          break;
        }
        else {
          // got last file node
          //kDebug(debugArea()) << "got doc";
          prev = last_index;
          break;
        }
      }
    }
  }

  if(prev.isValid()) {
    //kDebug(debugArea()) << "got prev node:" << prev;
    //kDebug(debugArea()) << "doc:" << ftpm->data(prev, Qt::DisplayRole).value<QString>();

    KTextEditor::Document *doc = model()->data(prev, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
    emit activateDocument(doc);
  }
  else {
    kDebug(debugArea()) << "didn't get prev node :(";
  }

  kDebug(debugArea()) << "END";
}

/*
plan:

default: select next sibling
if cur is a dir, select it

*/

void KateFileTree::slotDocumentNext()
{
  kDebug(debugArea()) << "BEGIN";

  KateFileTreeProxyModel *ftpm = static_cast<KateFileTreeProxyModel*>(model());

  QModelIndex current_index = currentIndex();
  int parent_row_count = ftpm->rowCount( ftpm->parent(current_index) );
  QModelIndex next;

  // scan down the tree skipping any dir nodes
  while(current_index.isValid()) {
    if(current_index.row() < parent_row_count-1) {
      current_index = ftpm->sibling(current_index.row()+1, current_index.column(), current_index);
      if(!current_index.isValid()) {
        break;
      }

      if(ftpm->isDir(current_index)) {
        // we have a dir node
        while(ftpm->isDir(current_index)) {
          current_index = ftpm->index(0, 0, current_index);
        }

        parent_row_count = ftpm->rowCount( ftpm->parent(current_index) );

        if(!ftpm->isDir(current_index)) {
          next = current_index;
          break;
        }
      } else { // found document item
        next = current_index;
        break;
      }
    }
    else {
      // select the parent's next sibling
      QModelIndex parent_index = ftpm->parent(current_index);
      int grandparent_row_count = ftpm->rowCount( ftpm->parent(parent_index) );

      current_index = parent_index;
      parent_row_count = grandparent_row_count;

      // at least if we're not past the last node
      if(!current_index.isValid()) {
        // past the root node here, try and wrap arround
        QModelIndex last_index = ftpm->index(0, 0, QModelIndex());
        if(!last_index.isValid()) {
          break;
        }

        if(ftpm->isDir(last_index)) {
          // last node is a dir, select first child row
          while(ftpm->isDir(last_index)) {
            if(ftpm->rowCount(last_index)) {
              // has children, select first
              last_index = ftpm->index(0, 0, last_index);
            }
          }

          next = last_index;
          break;
        }
        else {
          // got first file node
          next = last_index;
          break;
        }
      }
    }
  }

  if(next.isValid()) {
    //kDebug(debugArea()) << "got next node:" << next;
    //kDebug(debugArea()) << "doc:" << ftpm->data(next, Qt::DisplayRole).value<QString>();

    KTextEditor::Document *doc = model()->data(next, KateFileTreeModel::DocumentRole).value<KTextEditor::Document *>();
    emit activateDocument(doc);
  }
  else {
    kDebug(debugArea()) << "didn't get next node :(";
  }

  kDebug(debugArea()) << "END";
}
//END KateFileTree

// kate: space-indent on; indent-width 2; replace-tabs on;
<|endoftext|>


<commit_before>//
// Copyleft 2011 RIME Developers
// License: GPLv3
//
// 2011-12-18 GONG Chen <chen.sst@gmail.com>
//
#include <boost/bind.hpp>
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/config.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/key_event.h>
#include <rime/schema.h>
#include <rime/gear/ascii_composer.h>

namespace rime {

static struct AsciiModeSwitchStyleDefinition {
  const char* repr;
  AsciiModeSwitchStyle style;
} ascii_mode_switch_styles[] = {
  { "inline_ascii", kAsciiModeSwitchInline },
  { "commit_text", kAsciiModeSwitchCommitText },
  { "commit_code", kAsciiModeSwitchCommitCode },
  { NULL, kAsciiModeSwitchNoop }
};

static void load_bindings(const ConfigMapPtr &src,
                          AsciiModeSwitchKeyBindings* dest) {
  if (!src) return;
  for (ConfigMap::Iterator it = src->begin();
       it != src->end(); ++it) {
    ConfigValuePtr value(As<ConfigValue>(it->second));
    if (!value) continue;
    AsciiModeSwitchStyleDefinition* p = ascii_mode_switch_styles;
    while (p->repr && p->repr != value->str())
      ++p;
    if (p->style == kAsciiModeSwitchNoop)
      continue;
    KeyEvent ke;
    if (!ke.Parse(it->first) || ke.modifier() != 0) {
      LOG(WARNING) << "invalid ascii mode switch key: " << it->first;
      continue;
    }
    // save binding
    (*dest)[ke.keycode()] = p->style;
  }
}

AsciiComposer::AsciiComposer(Engine *engine)
    : Processor(engine),
      caps_lock_switch_style_(kAsciiModeSwitchNoop),
      good_old_caps_lock_(false),
      toggle_with_caps_(false),
      shift_key_pressed_(false),
      ctrl_key_pressed_(false) {
  LoadConfig(engine->schema());
}

Processor::Result AsciiComposer::ProcessKeyEvent(const KeyEvent& key_event) {
  if ((key_event.shift() && key_event.ctrl()) ||
      key_event.alt() || key_event.super()) {
    shift_key_pressed_ = ctrl_key_pressed_ = false;
    return kNoop;
  }
  if (caps_lock_switch_style_ != kAsciiModeSwitchNoop) {
    Result result = ProcessCapsLock(key_event);
    if (result != kNoop)
      return result;
  }
  int ch = key_event.keycode();
  bool is_shift = (ch == XK_Shift_L || ch == XK_Shift_R);
  bool is_ctrl = (ch == XK_Control_L || ch == XK_Control_R);
  if (is_shift || is_ctrl) {
    if (key_event.release()) {
      if (shift_key_pressed_ || ctrl_key_pressed_) {
        ToggleAsciiModeWithKey(ch);
        shift_key_pressed_ = ctrl_key_pressed_ = false;
        return kRejected;
      }
    }
    else {  // start pressing
      if (is_shift)
        shift_key_pressed_ = true;
      else
        ctrl_key_pressed_ = true;
    }
    return kNoop;
  }
  // other keys
  shift_key_pressed_ = ctrl_key_pressed_ = false;
  Context *ctx = engine_->context();
  bool ascii_mode = ctx->get_option("ascii_mode");
  if (ascii_mode) {
    if (!ctx->IsComposing()) {
      return kRejected;  // direct commit
    }
    // edit inline ascii
    if (!key_event.release() && !key_event.ctrl() &&
        ch >= 0x20 && ch < 0x80) {
      ctx->PushInput(ch);
      return kAccepted;
    }
  }
  return kNoop;
}

Processor::Result AsciiComposer::ProcessCapsLock(const KeyEvent& key_event) {
  int ch = key_event.keycode();
  if (ch == XK_Caps_Lock) {
    if (!key_event.release()) {
      shift_key_pressed_ = ctrl_key_pressed_ = false;
      // temprarily disable good-old (uppercase) Caps Lock as mode switch key
      // in case the user switched to ascii mode with other keys, eg. with Shift
      if (good_old_caps_lock_ && !toggle_with_caps_) {
        Context *ctx = engine_->context();
        bool ascii_mode = ctx->get_option("ascii_mode");
        if (ascii_mode) {
          return kRejected;
        }
      }
      toggle_with_caps_ = !key_event.caps();
      // NOTE: for Linux, Caps Lock modifier is clear when we are about to
      // turn it on; for Windows it is the opposite:
      // Caps Lock modifier has been set before we process VK_CAPITAL.
      // here we assume IBus' behavior and invert caps with ! operation.
      SwitchAsciiMode(!key_event.caps(), caps_lock_switch_style_);
      return kAccepted;
    }
    else {
      return kRejected;
    }
  }
  if (key_event.caps()) {
    if (!good_old_caps_lock_ &&
        !key_event.release() && !key_event.ctrl() &&
        isascii(ch) && isalpha(ch)) {
      // output ascii characters ignoring Caps Lock
      if (islower(ch))
        ch = toupper(ch);
      else if (isupper(ch))
        ch = tolower(ch);
      engine_->sink()(std::string(1, ch));
      return kAccepted;
    }
    else {
      return kRejected;
    }
  }
  return kNoop;
}

void AsciiComposer::LoadConfig(Schema* schema) {
  bindings_.clear();
  caps_lock_switch_style_ = kAsciiModeSwitchNoop;
  good_old_caps_lock_ = false;
  if (!schema) return;
  scoped_ptr<Config> preset_config(
      Config::Require("config")->Create("default"));
  if (preset_config) {
    preset_config->GetBool("ascii_composer/good_old_caps_lock",
                           &good_old_caps_lock_);
  }
  Config *config = schema->config();
  ConfigMapPtr  bindings = config->GetMap("ascii_composer/switch_key");
  if (!bindings) {
    if (!preset_config) {
      LOG(ERROR) << "Error importing preset ascii bindings.";
      return;
    }
    bindings = preset_config->GetMap("ascii_composer/switch_key");
    if (!bindings) {
      LOG(WARNING) << "missing preset ascii bindings.";
      return;
    }
  }
  load_bindings(bindings, &bindings_);
  AsciiModeSwitchKeyBindings::const_iterator it = bindings_.find(XK_Caps_Lock);
  if (it != bindings_.end()) {
    caps_lock_switch_style_ = it->second;
    if (caps_lock_switch_style_ == kAsciiModeSwitchInline) // cannot do that
      caps_lock_switch_style_ = kAsciiModeSwitchCommitCode;
  }
}

bool AsciiComposer::ToggleAsciiModeWithKey(int key_code) {
  AsciiModeSwitchKeyBindings::const_iterator it = bindings_.find(key_code);
  if (it == bindings_.end())
    return false;
  AsciiModeSwitchStyle style = it->second;
  Context *ctx = engine_->context();
  bool ascii_mode = !ctx->get_option("ascii_mode");
  SwitchAsciiMode(ascii_mode, style);
  toggle_with_caps_ = (key_code == XK_Caps_Lock);
  return true;
}

void AsciiComposer::SwitchAsciiMode(bool ascii_mode,
                                    AsciiModeSwitchStyle style) {
  DLOG(INFO) << "ascii mode: " << ascii_mode << ", switch style: " << style;
  Context *ctx = engine_->context();
  if (ctx->IsComposing()) {
    connection_.disconnect();
    // temporary ascii mode in desired manner
    if (style == kAsciiModeSwitchInline) {
      LOG(INFO) << "converting current composition to "
                << (ascii_mode ? "ascii" : "non-ascii") << " mode.";
      if (ascii_mode) {
        connection_ = ctx->update_notifier().connect(
            boost::bind(&AsciiComposer::OnContextUpdate, this, _1));
      }
    }
    else if (style == kAsciiModeSwitchCommitText) {
      ctx->ConfirmCurrentSelection();
    }
    else if (style == kAsciiModeSwitchCommitCode) {
      ctx->ClearNonConfirmedComposition();
      ctx->Commit();
    }
  }
  // refresh non-confirmed composition with new mode
  ctx->set_option("ascii_mode", ascii_mode);
}

void AsciiComposer::OnContextUpdate(Context *ctx) {
  if (!ctx->IsComposing()) {
    connection_.disconnect();
    // quit temporary ascii mode
    ctx->set_option("ascii_mode", false);
  }
}

}  // namespace rime
<commit_msg>fix googlecode Issue 444: fail to toggle back from ascii_mode with Control+space.<commit_after>//
// Copyleft 2011 RIME Developers
// License: GPLv3
//
// 2011-12-18 GONG Chen <chen.sst@gmail.com>
//
#include <boost/bind.hpp>
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/config.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/key_event.h>
#include <rime/schema.h>
#include <rime/gear/ascii_composer.h>

namespace rime {

static struct AsciiModeSwitchStyleDefinition {
  const char* repr;
  AsciiModeSwitchStyle style;
} ascii_mode_switch_styles[] = {
  { "inline_ascii", kAsciiModeSwitchInline },
  { "commit_text", kAsciiModeSwitchCommitText },
  { "commit_code", kAsciiModeSwitchCommitCode },
  { NULL, kAsciiModeSwitchNoop }
};

static void load_bindings(const ConfigMapPtr &src,
                          AsciiModeSwitchKeyBindings* dest) {
  if (!src) return;
  for (ConfigMap::Iterator it = src->begin();
       it != src->end(); ++it) {
    ConfigValuePtr value(As<ConfigValue>(it->second));
    if (!value) continue;
    AsciiModeSwitchStyleDefinition* p = ascii_mode_switch_styles;
    while (p->repr && p->repr != value->str())
      ++p;
    if (p->style == kAsciiModeSwitchNoop)
      continue;
    KeyEvent ke;
    if (!ke.Parse(it->first) || ke.modifier() != 0) {
      LOG(WARNING) << "invalid ascii mode switch key: " << it->first;
      continue;
    }
    // save binding
    (*dest)[ke.keycode()] = p->style;
  }
}

AsciiComposer::AsciiComposer(Engine *engine)
    : Processor(engine),
      caps_lock_switch_style_(kAsciiModeSwitchNoop),
      good_old_caps_lock_(false),
      toggle_with_caps_(false),
      shift_key_pressed_(false),
      ctrl_key_pressed_(false) {
  LoadConfig(engine->schema());
}

Processor::Result AsciiComposer::ProcessKeyEvent(const KeyEvent& key_event) {
  if ((key_event.shift() && key_event.ctrl()) ||
      key_event.alt() || key_event.super()) {
    shift_key_pressed_ = ctrl_key_pressed_ = false;
    return kNoop;
  }
  if (caps_lock_switch_style_ != kAsciiModeSwitchNoop) {
    Result result = ProcessCapsLock(key_event);
    if (result != kNoop)
      return result;
  }
  int ch = key_event.keycode();
  bool is_shift = (ch == XK_Shift_L || ch == XK_Shift_R);
  bool is_ctrl = (ch == XK_Control_L || ch == XK_Control_R);
  if (is_shift || is_ctrl) {
    if (key_event.release()) {
      if (shift_key_pressed_ || ctrl_key_pressed_) {
        ToggleAsciiModeWithKey(ch);
        shift_key_pressed_ = ctrl_key_pressed_ = false;
        return kRejected;
      }
    }
    else {  // start pressing
      if (is_shift)
        shift_key_pressed_ = true;
      else
        ctrl_key_pressed_ = true;
    }
    return kNoop;
  }
  // other keys
  shift_key_pressed_ = ctrl_key_pressed_ = false;
  if (key_event.ctrl()) {
    return kNoop;  // possible key binding Control+x
  }
  Context *ctx = engine_->context();
  bool ascii_mode = ctx->get_option("ascii_mode");
  if (ascii_mode) {
    if (!ctx->IsComposing()) {
      return kRejected;  // direct commit
    }
    // edit inline ascii string
    if (!key_event.release() && ch >= 0x20 && ch < 0x80) {
      ctx->PushInput(ch);
      return kAccepted;
    }
  }
  return kNoop;
}

Processor::Result AsciiComposer::ProcessCapsLock(const KeyEvent& key_event) {
  int ch = key_event.keycode();
  if (ch == XK_Caps_Lock) {
    if (!key_event.release()) {
      shift_key_pressed_ = ctrl_key_pressed_ = false;
      // temprarily disable good-old (uppercase) Caps Lock as mode switch key
      // in case the user switched to ascii mode with other keys, eg. with Shift
      if (good_old_caps_lock_ && !toggle_with_caps_) {
        Context *ctx = engine_->context();
        bool ascii_mode = ctx->get_option("ascii_mode");
        if (ascii_mode) {
          return kRejected;
        }
      }
      toggle_with_caps_ = !key_event.caps();
      // NOTE: for Linux, Caps Lock modifier is clear when we are about to
      // turn it on; for Windows it is the opposite:
      // Caps Lock modifier has been set before we process VK_CAPITAL.
      // here we assume IBus' behavior and invert caps with ! operation.
      SwitchAsciiMode(!key_event.caps(), caps_lock_switch_style_);
      return kAccepted;
    }
    else {
      return kRejected;
    }
  }
  if (key_event.caps()) {
    if (!good_old_caps_lock_ &&
        !key_event.release() && !key_event.ctrl() &&
        isascii(ch) && isalpha(ch)) {
      // output ascii characters ignoring Caps Lock
      if (islower(ch))
        ch = toupper(ch);
      else if (isupper(ch))
        ch = tolower(ch);
      engine_->sink()(std::string(1, ch));
      return kAccepted;
    }
    else {
      return kRejected;
    }
  }
  return kNoop;
}

void AsciiComposer::LoadConfig(Schema* schema) {
  bindings_.clear();
  caps_lock_switch_style_ = kAsciiModeSwitchNoop;
  good_old_caps_lock_ = false;
  if (!schema) return;
  scoped_ptr<Config> preset_config(
      Config::Require("config")->Create("default"));
  if (preset_config) {
    preset_config->GetBool("ascii_composer/good_old_caps_lock",
                           &good_old_caps_lock_);
  }
  Config *config = schema->config();
  ConfigMapPtr  bindings = config->GetMap("ascii_composer/switch_key");
  if (!bindings) {
    if (!preset_config) {
      LOG(ERROR) << "Error importing preset ascii bindings.";
      return;
    }
    bindings = preset_config->GetMap("ascii_composer/switch_key");
    if (!bindings) {
      LOG(WARNING) << "missing preset ascii bindings.";
      return;
    }
  }
  load_bindings(bindings, &bindings_);
  AsciiModeSwitchKeyBindings::const_iterator it = bindings_.find(XK_Caps_Lock);
  if (it != bindings_.end()) {
    caps_lock_switch_style_ = it->second;
    if (caps_lock_switch_style_ == kAsciiModeSwitchInline) // cannot do that
      caps_lock_switch_style_ = kAsciiModeSwitchCommitCode;
  }
}

bool AsciiComposer::ToggleAsciiModeWithKey(int key_code) {
  AsciiModeSwitchKeyBindings::const_iterator it = bindings_.find(key_code);
  if (it == bindings_.end())
    return false;
  AsciiModeSwitchStyle style = it->second;
  Context *ctx = engine_->context();
  bool ascii_mode = !ctx->get_option("ascii_mode");
  SwitchAsciiMode(ascii_mode, style);
  toggle_with_caps_ = (key_code == XK_Caps_Lock);
  return true;
}

void AsciiComposer::SwitchAsciiMode(bool ascii_mode,
                                    AsciiModeSwitchStyle style) {
  DLOG(INFO) << "ascii mode: " << ascii_mode << ", switch style: " << style;
  Context *ctx = engine_->context();
  if (ctx->IsComposing()) {
    connection_.disconnect();
    // temporary ascii mode in desired manner
    if (style == kAsciiModeSwitchInline) {
      LOG(INFO) << "converting current composition to "
                << (ascii_mode ? "ascii" : "non-ascii") << " mode.";
      if (ascii_mode) {
        connection_ = ctx->update_notifier().connect(
            boost::bind(&AsciiComposer::OnContextUpdate, this, _1));
      }
    }
    else if (style == kAsciiModeSwitchCommitText) {
      ctx->ConfirmCurrentSelection();
    }
    else if (style == kAsciiModeSwitchCommitCode) {
      ctx->ClearNonConfirmedComposition();
      ctx->Commit();
    }
  }
  // refresh non-confirmed composition with new mode
  ctx->set_option("ascii_mode", ascii_mode);
}

void AsciiComposer::OnContextUpdate(Context *ctx) {
  if (!ctx->IsComposing()) {
    connection_.disconnect();
    // quit temporary ascii mode
    ctx->set_option("ascii_mode", false);
  }
}

}  // namespace rime
<|endoftext|>


<commit_before>#include <algorithm>
#include <string>
#include <tuple>
#include <vector>
#include "xUnit++/IOutput.h"
#include "xUnit++/xUnitTestRunner.h"
#include "xUnit++/xUnitTime.h"
#include "xUnit++/xUnit++.h"

using xUnitpp::Assert;

SUITE(Theory)
{

void TheoryUnderTest(int x)
{
    Assert.True(x == 0 || x == 1);
}

struct TheoryFixture
{
private:
    struct : xUnitpp::IOutput
    {
        virtual void ReportStart(const xUnitpp::TestDetails &) override
        {
        }

        virtual void ReportFailure(const xUnitpp::TestDetails &, const std::string &, const xUnitpp::LineInfo &) override
        {
        }

        virtual void ReportSkip(const xUnitpp::TestDetails &, const std::string &) override
        {
        }

        virtual void ReportFinish(const xUnitpp::TestDetails &, xUnitpp::Time::Duration) override
        {
        }

        virtual void ReportAllTestsComplete(size_t, size_t, size_t, xUnitpp::Time::Duration) override
        {
        }
    } emptyReporter;

public:
    TheoryFixture()
        : localRunner(emptyReporter)
    {
    }

    template<typename TTheoryData>
    void Register(const std::string &name, TTheoryData &&theoryData)
    {
        xUnitpp::TestCollection::Register reg(collection, &TheoryUnderTest, theoryData, name, "Theory", attributes, -1, __FILE__, __LINE__);
    }

    void Run()
    {
        localRunner.RunTests([](const xUnitpp::TestDetails &) { return true; },
            collection.Tests(), xUnitpp::Time::Duration::zero(), 0);
    }

    template<typename TTheoryData>
    void RegisterAndRun(const std::string &name, TTheoryData &&theoryData)
    {
        Register(name, theoryData);

        Run();
    }

    xUnitpp::AttributeCollection attributes;
    xUnitpp::TestCollection collection;
    xUnitpp::TestRunner localRunner;
};

std::vector<std::tuple<int>> RawFunctionProvider()
{
    std::tuple<int> tuples[] =
    {
        std::make_tuple(0),
        std::make_tuple(1),
        std::make_tuple(2),
        std::make_tuple(3),
        std::make_tuple(0)
    };

    return std::vector<std::tuple<int>>(std::begin(tuples), std::end(tuples));
}

FACT_FIXTURE(TheoriesAcceptRawFunctions, TheoryFixture)
{
    RegisterAndRun("TheoriesAcceptRawFunctions", RawFunctionProvider);
}

FACT_FIXTURE(TheoriesAcceptStdFunction, TheoryFixture)
{
    std::function<std::vector<std::tuple<int>>()> provider = RawFunctionProvider;

    RegisterAndRun("TheoriesAcceptStdFunction", provider);
}

FACT_FIXTURE(TheoriesAcceptFunctors, TheoryFixture)
{
    struct
    {
        std::vector<std::tuple<int>> operator()() const
        {
            return RawFunctionProvider();
        }
    } functor;

    RegisterAndRun("TheoriesAcceptFunctors", functor);
}

FACT_FIXTURE(TheoriesGetAllDataPassedToThem, TheoryFixture)
{
    std::vector<int> dataProvided;

    // !!! this line appears to fix a somewhat random buffer overrun bug
    // I am not sure why. Investigate later.
    dataProvided.reserve(5);

    auto doTheory = [&](int x) { dataProvided.push_back(x); };
    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider, "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__);

    Run();

    Assert.Equal(2, std::count(dataProvided.begin(), dataProvided.end(), 0));
    Assert.Equal(1, std::count(dataProvided.begin(), dataProvided.end(), 1));
    Assert.Equal(1, std::count(dataProvided.begin(), dataProvided.end(), 2));
    Assert.Equal(1, std::count(dataProvided.begin(), dataProvided.end(), 3));
}

FACT_FIXTURE(TheoriesCanBeSkipped, TheoryFixture)
{
    attributes.insert(std::make_pair("Skip", "Testing skip."));

    auto doTheory = [](int) { Assert.Fail("Should not be run."); };

    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider, "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__);

    Run();
}

ATTRIBUTES(TheoriesCanHaveAttributes, ("Cats", "Meow"))
DATA_THEORY(TheoriesCanHaveAttributes, (int), RawFunctionProvider)
{
    for (const auto &test : xUnitpp::TestCollection::Instance().Tests())
    {
        if (test.TestDetails().ShortName == "TheoriesCanHaveAttributes")
        {
            auto it = test.TestDetails().Attributes.find("Cats");
            Assert.True(it != test.TestDetails().Attributes.end());
            Assert.True(it->second == "Meow");
            return;
        }
    }

    Assert.Fail("Could not find self in test list.");
}

std::vector<std::tuple<std::string, std::vector<std::tuple<int, std::string>>>> ComplexProvider()
{
    std::vector<std::tuple<std::string, std::vector<std::tuple<int, std::string>>>> result;

    std::vector<std::tuple<int, std::string>> internal_vector;
    internal_vector.push_back(std::make_tuple(0, std::string("xyz")));

    result.push_back(std::make_tuple(std::string("abcd"), internal_vector));

    return result;
}

DATA_THEORY(TheoriesCanAcceptComplexObjects, (const std::string &, const std::vector<std::tuple<int, std::string>> &), ComplexProvider)
{
    // just existing is good enough
}

DATA_THEORY(TheoriesCanAcceptLambdas, (int, int),
    ([]() -> std::vector<std::tuple<int, int>>
    {
        std::vector<std::tuple<int, int>> data;
        data.push_back(std::make_tuple(0, 0));
        return data;
    })
)
{
    // just existing is good enough
}

THEORY(TestingSuccessfulInlineTheory, (int, const std::string &),
    std::make_tuple(0, ""),
    std::make_tuple(0, ""),
    std::make_tuple(0, ""),
    std::make_tuple(0, ""))
{
    // just existing is good enough
}

THEORY(TestingFailingfulInlineTheory, (int, const std::string &),
    std::make_tuple(0, ""),
    std::make_tuple(1, ""),
    std::make_tuple(1, ""),
    std::make_tuple(1, ""))
{
    // just existing is good enough
}

}
<commit_msg>forgot to implement these two tests<commit_after>#include <algorithm>
#include <string>
#include <tuple>
#include <vector>
#include "xUnit++/IOutput.h"
#include "xUnit++/xUnitTestRunner.h"
#include "xUnit++/xUnitTime.h"
#include "xUnit++/xUnit++.h"

using xUnitpp::Assert;

SUITE(Theory)
{

void TheoryUnderTest(int x)
{
    Assert.True(x == 0 || x == 1);
}

struct TheoryFixture
{
private:
    struct : xUnitpp::IOutput
    {
        virtual void ReportStart(const xUnitpp::TestDetails &) override
        {
        }

        virtual void ReportFailure(const xUnitpp::TestDetails &, const std::string &, const xUnitpp::LineInfo &) override
        {
        }

        virtual void ReportSkip(const xUnitpp::TestDetails &, const std::string &) override
        {
        }

        virtual void ReportFinish(const xUnitpp::TestDetails &, xUnitpp::Time::Duration) override
        {
        }

        virtual void ReportAllTestsComplete(size_t, size_t, size_t, xUnitpp::Time::Duration) override
        {
        }
    } emptyReporter;

public:
    TheoryFixture()
        : localRunner(emptyReporter)
    {
    }

    template<typename TTheoryData>
    void Register(const std::string &name, TTheoryData &&theoryData)
    {
        xUnitpp::TestCollection::Register reg(collection, &TheoryUnderTest, theoryData, name, "Theory", attributes, -1, __FILE__, __LINE__);
    }

    void Run()
    {
        localRunner.RunTests([](const xUnitpp::TestDetails &) { return true; },
            collection.Tests(), xUnitpp::Time::Duration::zero(), 0);
    }

    template<typename TTheoryData>
    void RegisterAndRun(const std::string &name, TTheoryData &&theoryData)
    {
        Register(name, theoryData);

        Run();
    }

    xUnitpp::AttributeCollection attributes;
    xUnitpp::TestCollection collection;
    xUnitpp::TestRunner localRunner;
};

std::vector<std::tuple<int>> RawFunctionProvider()
{
    std::tuple<int> tuples[] =
    {
        std::make_tuple(0),
        std::make_tuple(1),
        std::make_tuple(2),
        std::make_tuple(3),
        std::make_tuple(0)
    };

    return std::vector<std::tuple<int>>(std::begin(tuples), std::end(tuples));
}

FACT_FIXTURE(TheoriesAcceptRawFunctions, TheoryFixture)
{
    RegisterAndRun("TheoriesAcceptRawFunctions", RawFunctionProvider);
}

FACT_FIXTURE(TheoriesAcceptStdFunction, TheoryFixture)
{
    std::function<std::vector<std::tuple<int>>()> provider = RawFunctionProvider;

    RegisterAndRun("TheoriesAcceptStdFunction", provider);
}

FACT_FIXTURE(TheoriesAcceptFunctors, TheoryFixture)
{
    struct
    {
        std::vector<std::tuple<int>> operator()() const
        {
            return RawFunctionProvider();
        }
    } functor;

    RegisterAndRun("TheoriesAcceptFunctors", functor);
}

FACT_FIXTURE(TheoriesGetAllDataPassedToThem, TheoryFixture)
{
    std::vector<int> dataProvided;

    // !!! this line appears to fix a somewhat random buffer overrun bug
    // I am not sure why. Investigate later.
    dataProvided.reserve(5);

    auto doTheory = [&](int x) { dataProvided.push_back(x); };
    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider, "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__);

    Run();

    Assert.Equal(2, std::count(dataProvided.begin(), dataProvided.end(), 0));
    Assert.Equal(1, std::count(dataProvided.begin(), dataProvided.end(), 1));
    Assert.Equal(1, std::count(dataProvided.begin(), dataProvided.end(), 2));
    Assert.Equal(1, std::count(dataProvided.begin(), dataProvided.end(), 3));
}

FACT_FIXTURE(TheoriesCanBeSkipped, TheoryFixture)
{
    attributes.insert(std::make_pair("Skip", "Testing skip."));

    auto doTheory = [](int) { Assert.Fail("Should not be run."); };

    xUnitpp::TestCollection::Register reg(collection, doTheory, RawFunctionProvider, "TheoriesGetAllDataPassedToThem", "Theory", attributes, -1, __FILE__, __LINE__);

    Run();
}

ATTRIBUTES(TheoriesCanHaveAttributes, ("Cats", "Meow"))
DATA_THEORY(TheoriesCanHaveAttributes, (int), RawFunctionProvider)
{
    for (const auto &test : xUnitpp::TestCollection::Instance().Tests())
    {
        if (test.TestDetails().ShortName == "TheoriesCanHaveAttributes")
        {
            auto it = test.TestDetails().Attributes.find("Cats");
            Assert.True(it != test.TestDetails().Attributes.end());
            Assert.True(it->second == "Meow");
            return;
        }
    }

    Assert.Fail("Could not find self in test list.");
}

std::vector<std::tuple<std::string, std::vector<std::tuple<int, std::string>>>> ComplexProvider()
{
    std::vector<std::tuple<std::string, std::vector<std::tuple<int, std::string>>>> result;

    std::vector<std::tuple<int, std::string>> internal_vector;
    internal_vector.push_back(std::make_tuple(0, std::string("xyz")));

    result.push_back(std::make_tuple(std::string("abcd"), internal_vector));

    return result;
}

DATA_THEORY(TheoriesCanAcceptComplexObjects, (const std::string &, const std::vector<std::tuple<int, std::string>> &), ComplexProvider)
{
    // just existing is good enough
}

DATA_THEORY(TheoriesCanAcceptLambdas, (int, int),
    ([]() -> std::vector<std::tuple<int, int>>
    {
        std::vector<std::tuple<int, int>> data;
        data.push_back(std::make_tuple(0, 0));
        return data;
    })
)
{
    // just existing is good enough
}

THEORY(TestingSuccessfulInlineTheory, (int x, const std::string &str),
    std::make_tuple(0, ""),
    std::make_tuple(0, ""),
    std::make_tuple(0, ""),
    std::make_tuple(0, ""))
{
    Assert.Equal(0, x);
    Assert.Empty(str);
}

THEORY(TestingFailingInlineTheory, (int, const std::string &str),
    std::make_tuple(1, "a"),
    std::make_tuple(1, "b"),
    std::make_tuple(1, "c"),
    std::make_tuple(1, "d"))
{
    Assert.Throws<xUnitpp::xUnitAssert>([&]() { Assert.Empty(str); });
}

}
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "amr_includes.H"

static
void interpolate2ghost(fclaw2d_domain_t *domain,int fine_level,
                       fclaw_bool time_interp);

static
void copy2ghost(fclaw2d_domain_t *domain, int level,
                fclaw_bool read_parallel_patches);

static
void average2ghost(fclaw2d_domain_t *domain, int coarse_level,
                   fclaw_bool time_interp,
                   fclaw_bool read_parallel_patches);

void intralevel_ghost_copy(fclaw2d_domain_t* domain, int minlevel,
                           int maxlevel,
                           fclaw_bool read_parallel_patches)
{
    /* Copy between grids that are at the same level. */
    for(int level = maxlevel; level >= minlevel; level--)
    {
        copy2ghost(domain,level,read_parallel_patches);
    }
}

void fill_coarse_ghost(fclaw2d_domain_t *domain,
                       int mincoarse,
                       int maxcoarse,
                       fclaw_bool time_interp,
                       fclaw_bool read_parallel_patches)
{
    /* Average fine grids to coarse grid ghost cells */
    for(int level = maxcoarse; level >= mincoarse; level--)
    {
        average2ghost(domain,level,time_interp,read_parallel_patches);
    }
}

void fill_fine_ghost(fclaw2d_domain_t* domain, int minfine, int maxfine,
                     fclaw_bool time_interp)
{
    /* Interpolate from coarse grid to fine grid ghost */
    for(int level = maxfine; level >= minfine; level--)
    {
        interpolate2ghost(domain,level,time_interp);
    }
}

void fill_physical_ghost(fclaw2d_domain_t* domain, int minlevel, int maxlevel,
                         double t, fclaw_bool time_interp)
{
    for(int level = maxlevel; level >= minlevel; level--)
    {
        set_phys_bc(domain,level,t,time_interp);
    }
}

fclaw_bool fclaw2d_patch_is_remote(fclaw2d_patch_t *patch)
{
    return fclaw2d_patch_is_ghost(patch);
}

fclaw_bool fclaw2d_patch_is_local(fclaw2d_patch_t *patch)
{
    return !fclaw2d_patch_is_ghost(patch);
}

static
void copy2ghost(fclaw2d_domain_t *domain, int level,
                fclaw_bool read_parallel_patches)
{
    fclaw2d_exchange_info_t e_info;
    e_info.exchange_type = FCLAW2D_COPY;
    e_info.grid_type = FCLAW2D_IS_COARSE;
    e_info.time_interp = fclaw_false;
    e_info.read_parallel_patches = read_parallel_patches;

    /* face exchanges */
    fclaw2d_domain_iterate_level(domain, level, cb_face_fill,
                                 (void *) &e_info);

    /* corner exchanges */
    fclaw2d_domain_iterate_level(domain, level, cb_corner_fill,
                                 (void *) &e_info);

}

static
void average2ghost(fclaw2d_domain_t *domain, int coarse_level,
                   fclaw_bool time_interp,
                   fclaw_bool read_parallel_patches)
{
    fclaw2d_exchange_info_t e_info;
    e_info.time_interp = time_interp;
    e_info.read_parallel_patches = read_parallel_patches;
    e_info.exchange_type = FCLAW2D_AVERAGE;
    int fine_level = coarse_level + 1;

    /* Only update ghost cells at local boundaries */
    e_info.grid_type = FCLAW2D_IS_COARSE;

    /* Face average */
    fclaw2d_domain_iterate_level(domain, coarse_level,
                                 cb_face_fill, (void *) &e_info);

    /* Corner average */
    fclaw2d_domain_iterate_level(domain, coarse_level, cb_corner_fill,
                                 (void *) &e_info);

    if (read_parallel_patches)
    {
        /* Second pass : average from local fine grids to remote coarse grids. These
           coarse grids might be needed for interpolation later. */
        e_info.grid_type = FCLAW2D_IS_FINE;

        /* Face average */
        fclaw2d_domain_iterate_level(domain, fine_level,
                                     cb_face_fill, (void *) &e_info);

        /* Corner average */
        /* We can skip the corner update, since we don't need the corner ghost cell
           values for doing interpolation */
        /*
        fclaw2d_domain_iterate_level(domain, fine_level, cb_corner_average,
                                     (void *) &e_info);
        */
    }
}

static
void interpolate2ghost(fclaw2d_domain_t *domain,int fine_level,
                       fclaw_bool time_interp)
{
    fclaw2d_exchange_info_t e_info;
    e_info.time_interp = time_interp;
    e_info.level = fine_level;
    e_info.exchange_type = FCLAW2D_INTERPOLATE;

    int coarse_level = fine_level - 1;

    /* ----------------------------------------------------------
       First pass - iterate over coarse grids and update ghost
       cells on local fine grids.
       ---------------------------------------------------------- */

    /* Interpolation done over all patches */
    e_info.read_parallel_patches = fclaw_true;
    e_info.grid_type = FCLAW2D_IS_COARSE;

    /* Face interpolate */
    fclaw2d_domain_iterate_level(domain,coarse_level, cb_face_fill,
                                 (void *) &e_info);

    /* Corner interpolate */
    fclaw2d_domain_iterate_level(domain,coarse_level, cb_corner_fill,
                                 (void *) &e_info);

    /* -----------------------------------------------------
       Second pass - Iterate over local fine grids, looking
       for remote coarse grids we can use to fill in BCs at
       fine grid ghost cells along the parallel boundary
       ----------------------------------------------------- */

    e_info.grid_type = FCLAW2D_IS_FINE;

    /* Interpolate to faces at parallel boundaries from coarse grid ghost
       patches */
    fclaw2d_domain_iterate_level(domain, fine_level, cb_face_fill,
                                 (void *) &e_info);

    /* Interpolate to corners at parallel boundaries from coarse grid
       ghost patches */
    fclaw2d_domain_iterate_level(domain, fine_level, cb_corner_fill,
                                 (void *) &e_info);
}

/* -------------------------------------------------------------------
   Main routine in this file
   ------------------------------------------------------------------- */

/* ------------------------------------------------------------
   This does a complete exchange over all levels.

   -- Parallel ghost patches are exchanged at all levels
   -- Every level exchanges ghost cells with other patches
      at that level
   -- Every finer level exchanges with a coarser level
   -- No time interpolation is assumed, as all levels are time
      synchronized at this point.
   -- This the only routine that is called for the non-subcycled
      case.
   -- All levels will be updated in next update step, regardless of
      whether we are in the subcycled or non-subcycled case.

  The reason for two separate ghost cell exchange routines is that
  the logic here is considerably simpler than for the partial
  update used in intermediate steps in the subcycled case.
  ------------------------------------------------------------- */
void update_ghost_all_levels(fclaw2d_domain_t* domain,
                             fclaw2d_timer_names_t running)
{
    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_stop (&ddata->timers[running]);
    }
    fclaw2d_timer_start (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);

    const amr_options_t *gparms = get_domain_parms(domain);
    fclaw_bool verbose = gparms->verbosity;

    if (verbose)
    {
        cout << "Exchanging ghost patches across all levels " << endl;
    }

    int minlevel = domain->global_minlevel;
    int maxlevel = domain->global_maxlevel;

    /* No time interpolation, since levels are time synchronized */
    fclaw_bool time_interp = fclaw_false;
    double t = get_domain_time(domain);

    /* ---------------------------------------------------------
       Get coarse grid ghost cells ready to use for interpolation.
       Coarse ghost cells on ghost patches are not updated in
       this step.  Ghost patches do not yet have valid data, and
       so boundary patches will have to be updated after the exchange.
       ---------------------------------------------------------- */
    int mincoarse = minlevel;
    int maxcoarse = maxlevel-1;

    /* Copy ghost cells at coarse levels.  Include finest level, although it isn't
       needed immediately */
    fclaw_bool read_parallel_patches = fclaw_false;
    intralevel_ghost_copy(domain,minlevel,maxlevel,read_parallel_patches);

    /* Average fine grid data to the coarse grid. */
    fill_coarse_ghost(domain,mincoarse,maxcoarse, time_interp,
                      read_parallel_patches);

    /* Supply physical boundary conditions on coarse grid */
    fill_physical_ghost(domain,mincoarse,maxcoarse,t,time_interp);

    /* -------------------------------------------------------------
      Parallel ghost patch exchange
      -------------------------------------------------------------- */
    exchange_ghost_patch_data_all(domain);

    /* -------------------------------------------------------------
      Repeat above, but now with parallel ghost cells.
      This may involve lots of repeated worked.
      -------------------------------------------------------------- */

    /* Fill in ghost cells on parallel patch boundaries */
    read_parallel_patches = fclaw_false;
    intralevel_ghost_copy(domain,minlevel,maxlevel,
                          read_parallel_patches);

    /* Average fine grid data to the coarse grid. */
    fill_coarse_ghost(domain,mincoarse,maxcoarse, time_interp,
                      read_parallel_patches);

    /* Supply physical boundary conditions on coarse grid */
    fill_physical_ghost(domain,mincoarse,maxcoarse,t,time_interp);

    /* ---------------------------------------------------------
       Fill in fine grid data via interpolation.  Fine grid ghost
       cells on ghost patches are updated.  They must then be
       passed back to their home processor.
       ---------------------------------------------------------- */
    int minfine = minlevel+1;
    int maxfine = maxlevel;

    fill_fine_ghost(domain,minfine, maxfine,time_interp);

    /* Fill in fine grid ghost cells at physical boundaries. This is
     needed to make sure we have valid values in the fine grid corners at
     the physical boundaries. */
    fill_physical_ghost(domain,minfine,maxfine,t,time_interp);

    /* --------------------------------------------------------- */

    // Stop timing
    fclaw2d_timer_stop (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_start (&ddata->timers[running]);
    }
}

#if 0

/* ----------------------------------------------------------
   This does the intermediate ghost patch and ghost cell
   exchange needed by either the subcycled case or the non
   subcycled case.

   Assumptions going into this routine :
   -- coarse_level > global_minlevel
   -- Data at coarse_level-1 is time interpolated data
   -- This routine is never called in the non-subcycled case
   -- This should be more 'lightweight' than doing a complete
      exchange (across all levels) at each fine grid time
      step.  But it should be equivalent.

   ---------------------------------------------------------- */
void update_ghost_partial(fclaw2d_domain_t* domain, int coarse_level,
                          int fine_level,
                          subcycle_manager *a_time_stepper,
                          fclaw2d_timer_names_t running)
{
    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_stop (&ddata->timers[running]);
    }
    fclaw2d_timer_start (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);

    const amr_options_t *gparms = get_domain_parms(domain);
    fclaw_bool verbose = gparms->verbosity;

    int time_interp_level = coarse_level - 1;

    if (verbose)
    {
        cout << "Exchanging ghost patches from levels " <<
            coarse_level << " to " << fine_level << endl;
        if (!a_time_stepper->nosubcycle())
        {
            cout << "Time interpolated level is " <<
                time_interp_level << endl;
        }
    }

    /* Make available patches from levels coarse to fine */
    set_boundary_patch_ptrs(domain,time_interp_level, fine_level);

    /* Do parallel ghost exchange */
    exchange_ghost_patch_data_levels(domain,time_interp_level,
                                     fine_level);

    /* -------------------------------------------------------
       Do ghost cell exchange.
       ------------------------------------------------------- */
    double t = get_domain_time(domain); /* needed for phys. bc */
    /* Do all level exchanges first */
    for(int level = fine_level; level >= coarse_level; level--)
    {
        level_exchange(domain,level);
    }

    /* Then do exchanges with coarser level */
    fclaw_bool time_interp_vec[fine_level-coarse_level+1];
    for(int level = fine_level; level > coarse_level; level--)
    {
        time_interp_vec[level] = fclaw_false;
    }

    /* coarse level exchanges with a time interpolated level
       time_interp_level = coarse_level-1
    */
    time_interp_vec[coarse_level] = fclaw_true;
    for(int level = fine_level; level >= coarse_level; level--)
    {
        exchange_with_coarse(domain,level,t,time_interp_vec[level]);
    }

    fclaw_bool time_interp = fclaw_false;
    for (int level = fine_level; level >= coarse_level; level--)
    {
        set_phys_bc(domain,level,t,time_interp);
    }

    // Stop timing
    fclaw2d_timer_stop (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_start (&ddata->timers[running]);
    }
}
#endif
<commit_msg>Apply physical boundary conditions over all levels as final step<commit_after>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "amr_includes.H"

static
void interpolate2ghost(fclaw2d_domain_t *domain,int fine_level,
                       fclaw_bool time_interp);

static
void copy2ghost(fclaw2d_domain_t *domain, int level,
                fclaw_bool read_parallel_patches);

static
void average2ghost(fclaw2d_domain_t *domain, int coarse_level,
                   fclaw_bool time_interp,
                   fclaw_bool read_parallel_patches);

void intralevel_ghost_copy(fclaw2d_domain_t* domain, int minlevel,
                           int maxlevel,
                           fclaw_bool read_parallel_patches)
{
    /* Copy between grids that are at the same level. */
    for(int level = maxlevel; level >= minlevel; level--)
    {
        copy2ghost(domain,level,read_parallel_patches);
    }
}

void fill_coarse_ghost(fclaw2d_domain_t *domain,
                       int mincoarse,
                       int maxcoarse,
                       fclaw_bool time_interp,
                       fclaw_bool read_parallel_patches)
{
    /* Average fine grids to coarse grid ghost cells */
    for(int level = maxcoarse; level >= mincoarse; level--)
    {
        average2ghost(domain,level,time_interp,read_parallel_patches);
    }
}

void fill_fine_ghost(fclaw2d_domain_t* domain, int minfine, int maxfine,
                     fclaw_bool time_interp)
{
    /* Interpolate from coarse grid to fine grid ghost */
    for(int level = maxfine; level >= minfine; level--)
    {
        interpolate2ghost(domain,level,time_interp);
    }
}

void fill_physical_ghost(fclaw2d_domain_t* domain, int minlevel, int maxlevel,
                         double t, fclaw_bool time_interp)
{
    for(int level = maxlevel; level >= minlevel; level--)
    {
        set_phys_bc(domain,level,t,time_interp);
    }
}

fclaw_bool fclaw2d_patch_is_remote(fclaw2d_patch_t *patch)
{
    return fclaw2d_patch_is_ghost(patch);
}

fclaw_bool fclaw2d_patch_is_local(fclaw2d_patch_t *patch)
{
    return !fclaw2d_patch_is_ghost(patch);
}

static
void copy2ghost(fclaw2d_domain_t *domain, int level,
                fclaw_bool read_parallel_patches)
{
    fclaw2d_exchange_info_t e_info;
    e_info.exchange_type = FCLAW2D_COPY;
    e_info.grid_type = FCLAW2D_IS_COARSE;
    e_info.time_interp = fclaw_false;
    e_info.read_parallel_patches = read_parallel_patches;

    /* face exchanges */
    fclaw2d_domain_iterate_level(domain, level, cb_face_fill,
                                 (void *) &e_info);

    /* corner exchanges */
    fclaw2d_domain_iterate_level(domain, level, cb_corner_fill,
                                 (void *) &e_info);

}

static
void average2ghost(fclaw2d_domain_t *domain, int coarse_level,
                   fclaw_bool time_interp,
                   fclaw_bool read_parallel_patches)
{
    fclaw2d_exchange_info_t e_info;
    e_info.time_interp = time_interp;
    e_info.read_parallel_patches = read_parallel_patches;
    e_info.exchange_type = FCLAW2D_AVERAGE;
    int fine_level = coarse_level + 1;

    /* Only update ghost cells at local boundaries */
    e_info.grid_type = FCLAW2D_IS_COARSE;

    /* Face average */
    fclaw2d_domain_iterate_level(domain, coarse_level,
                                 cb_face_fill, (void *) &e_info);

    /* Corner average */
    fclaw2d_domain_iterate_level(domain, coarse_level, cb_corner_fill,
                                 (void *) &e_info);

    if (read_parallel_patches)
    {
        /* Second pass : average from local fine grids to remote coarse grids. These
           coarse grids might be needed for interpolation later. */
        e_info.grid_type = FCLAW2D_IS_FINE;

        /* Face average */
        fclaw2d_domain_iterate_level(domain, fine_level,
                                     cb_face_fill, (void *) &e_info);

        /* Corner average */
        /* We can skip the corner update, since we don't need the corner ghost cell
           values for doing interpolation */
        /*
        fclaw2d_domain_iterate_level(domain, fine_level, cb_corner_average,
                                     (void *) &e_info);
        */
    }
}

static
void interpolate2ghost(fclaw2d_domain_t *domain,int fine_level,
                       fclaw_bool time_interp)
{
    fclaw2d_exchange_info_t e_info;
    e_info.time_interp = time_interp;
    e_info.level = fine_level;
    e_info.exchange_type = FCLAW2D_INTERPOLATE;

    int coarse_level = fine_level - 1;

    /* ----------------------------------------------------------
       First pass - iterate over coarse grids and update ghost
       cells on local fine grids.
       ---------------------------------------------------------- */

    /* Interpolation done over all patches */
    e_info.read_parallel_patches = fclaw_true;
    e_info.grid_type = FCLAW2D_IS_COARSE;

    /* Face interpolate */
    fclaw2d_domain_iterate_level(domain,coarse_level, cb_face_fill,
                                 (void *) &e_info);

    /* Corner interpolate */
    fclaw2d_domain_iterate_level(domain,coarse_level, cb_corner_fill,
                                 (void *) &e_info);

    /* -----------------------------------------------------
       Second pass - Iterate over local fine grids, looking
       for remote coarse grids we can use to fill in BCs at
       fine grid ghost cells along the parallel boundary
       ----------------------------------------------------- */

    e_info.grid_type = FCLAW2D_IS_FINE;

    /* Interpolate to faces at parallel boundaries from coarse grid ghost
       patches */
    fclaw2d_domain_iterate_level(domain, fine_level, cb_face_fill,
                                 (void *) &e_info);

    /* Interpolate to corners at parallel boundaries from coarse grid
       ghost patches */
    fclaw2d_domain_iterate_level(domain, fine_level, cb_corner_fill,
                                 (void *) &e_info);
}

/* -------------------------------------------------------------------
   Main routine in this file
   ------------------------------------------------------------------- */

/* ------------------------------------------------------------
   This does a complete exchange over all levels.

   -- Parallel ghost patches are exchanged at all levels
   -- Every level exchanges ghost cells with other patches
      at that level
   -- Every finer level exchanges with a coarser level
   -- No time interpolation is assumed, as all levels are time
      synchronized at this point.
   -- This the only routine that is called for the non-subcycled
      case.
   -- All levels will be updated in next update step, regardless of
      whether we are in the subcycled or non-subcycled case.

  The reason for two separate ghost cell exchange routines is that
  the logic here is considerably simpler than for the partial
  update used in intermediate steps in the subcycled case.
  ------------------------------------------------------------- */
void update_ghost_all_levels(fclaw2d_domain_t* domain,
                             fclaw2d_timer_names_t running)
{
    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_stop (&ddata->timers[running]);
    }
    fclaw2d_timer_start (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);

    const amr_options_t *gparms = get_domain_parms(domain);
    fclaw_bool verbose = gparms->verbosity;

    if (verbose)
    {
        cout << "Exchanging ghost patches across all levels " << endl;
    }

    int minlevel = domain->global_minlevel;
    int maxlevel = domain->global_maxlevel;

    /* No time interpolation, since levels are time synchronized */
    fclaw_bool time_interp = fclaw_false;
    double t = get_domain_time(domain);

    /* ---------------------------------------------------------
       Get coarse grid ghost cells ready to use for interpolation.
       Coarse ghost cells on ghost patches are not updated in
       this step.  Ghost patches do not yet have valid data, and
       so boundary patches will have to be updated after the exchange.
       ---------------------------------------------------------- */
    int mincoarse = minlevel;
    int maxcoarse = maxlevel-1;

    /* Copy ghost cells at coarse levels.  Include finest level, although it isn't
       needed immediately */
    fclaw_bool read_parallel_patches = fclaw_false;
    intralevel_ghost_copy(domain,minlevel,maxlevel,read_parallel_patches);

    /* Average fine grid data to the coarse grid. */
    fill_coarse_ghost(domain,mincoarse,maxcoarse, time_interp,
                      read_parallel_patches);

    /* Supply physical boundary conditions on coarse grid */
    fill_physical_ghost(domain,mincoarse,maxcoarse,t,time_interp);

    if (domain->mpisize > 1)
    {
        /* -------------------------------------------------------------
           Parallel ghost patch exchange
           -------------------------------------------------------------- */
        exchange_ghost_patch_data_all(domain);

        /* -------------------------------------------------------------
           Repeat above, but now with parallel ghost cells.
           This may involve lots of repeated worked.
           -------------------------------------------------------------- */

        /* Fill in ghost cells on parallel patch boundaries */
        read_parallel_patches = fclaw_true;
        intralevel_ghost_copy(domain,minlevel,maxlevel,
                              read_parallel_patches);

        /* Average fine grid data to the coarse grid. */
        fill_coarse_ghost(domain,mincoarse,maxcoarse, time_interp,
                          read_parallel_patches);

        /* Supply physical boundary conditions on coarse grid */
        fill_physical_ghost(domain,mincoarse,maxcoarse,t,time_interp);
    }

    /* ---------------------------------------------------------
       Fill in fine grid data via interpolation.  Fine grid ghost
       cells on ghost patches are updated.  They must then be
       passed back to their home processor.
       ---------------------------------------------------------- */
    int minfine = minlevel+1;
    int maxfine = maxlevel;

    fill_fine_ghost(domain,minfine, maxfine,time_interp);

    /* --------------------------------------------------------- */
    /* Do a final fill in of boundary conditions of all physical
       values */
    fill_physical_ghost(domain,minlevel,maxlevel,t,time_interp);

    /* --------------------------------------------------------- */

    // Stop timing
    fclaw2d_timer_stop (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_start (&ddata->timers[running]);
    }
}

#if 0

/* ----------------------------------------------------------
   This does the intermediate ghost patch and ghost cell
   exchange needed by either the subcycled case or the non
   subcycled case.

   Assumptions going into this routine :
   -- coarse_level > global_minlevel
   -- Data at coarse_level-1 is time interpolated data
   -- This routine is never called in the non-subcycled case
   -- This should be more 'lightweight' than doing a complete
      exchange (across all levels) at each fine grid time
      step.  But it should be equivalent.

   ---------------------------------------------------------- */
void update_ghost_partial(fclaw2d_domain_t* domain, int coarse_level,
                          int fine_level,
                          subcycle_manager *a_time_stepper,
                          fclaw2d_timer_names_t running)
{
    fclaw2d_domain_data_t *ddata = get_domain_data(domain);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_stop (&ddata->timers[running]);
    }
    fclaw2d_timer_start (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);

    const amr_options_t *gparms = get_domain_parms(domain);
    fclaw_bool verbose = gparms->verbosity;

    int time_interp_level = coarse_level - 1;

    if (verbose)
    {
        cout << "Exchanging ghost patches from levels " <<
            coarse_level << " to " << fine_level << endl;
        if (!a_time_stepper->nosubcycle())
        {
            cout << "Time interpolated level is " <<
                time_interp_level << endl;
        }
    }

    /* Make available patches from levels coarse to fine */
    set_boundary_patch_ptrs(domain,time_interp_level, fine_level);

    /* Do parallel ghost exchange */
    exchange_ghost_patch_data_levels(domain,time_interp_level,
                                     fine_level);

    /* -------------------------------------------------------
       Do ghost cell exchange.
       ------------------------------------------------------- */
    double t = get_domain_time(domain); /* needed for phys. bc */
    /* Do all level exchanges first */
    for(int level = fine_level; level >= coarse_level; level--)
    {
        level_exchange(domain,level);
    }

    /* Then do exchanges with coarser level */
    fclaw_bool time_interp_vec[fine_level-coarse_level+1];
    for(int level = fine_level; level > coarse_level; level--)
    {
        time_interp_vec[level] = fclaw_false;
    }

    /* coarse level exchanges with a time interpolated level
       time_interp_level = coarse_level-1
    */
    time_interp_vec[coarse_level] = fclaw_true;
    for(int level = fine_level; level >= coarse_level; level--)
    {
        exchange_with_coarse(domain,level,t,time_interp_vec[level]);
    }

    fclaw_bool time_interp = fclaw_false;
    for (int level = fine_level; level >= coarse_level; level--)
    {
        set_phys_bc(domain,level,t,time_interp);
    }

    // Stop timing
    fclaw2d_timer_stop (&ddata->timers[FCLAW2D_TIMER_EXCHANGE]);
    if (running != FCLAW2D_TIMER_NONE) {
        fclaw2d_timer_start (&ddata->timers[running]);
    }
}
#endif
<|endoftext|>