Copyright 2000-2016 Horde LLC (http://www.horde.org/) See the enclosed file COPYING for license information (GPL). If you did not receive this file, see http://www.horde.org/licenses/gpl.
Author: Anil Madhavapeddy (avsm@horde.org)
Author: Michael Slusarz (slusarz@horde.org)
Exemple #1
0
 public function render()
 {
     // need the checkout
     $checkOut = $GLOBALS['VC']->checkout($this->_file->getPath(), $this->_revision);
     // Pretty-print the checked out copy */
     if ($this->_file->mimeType == 'application/octet-stream') {
         $this->_view->mimeType = 'text/plain';
     } else {
         $this->_view->mimeType = $this->_file->mimeType;
     }
     $this->_view->title = $this->_file->getFileName();
     $this->_view->pretty = Chora::pretty($this->_view->mimeType, $checkOut);
     if ($this->_view->mimeType == 'text/html') {
         $this->_view->pretty->setConfigParam('inline', true);
     }
     return $this->_view->render('app/views/file/html.html.php');
 }
Exemple #2
0
}
if (!$VC->isValidRevision($rev)) {
    Chora::fatal(sprintf(_("Revision %s not found"), $rev), '404 Not Found');
}
try {
    $lines = $VC->annotate($fl, $rev);
} catch (Horde_Vcs_Exception $e) {
    Chora::fatal($e);
}
$title = sprintf(_("Source Annotation (revision %s) for:"), $rev);
$page_output->addScriptFile('annotate.js');
$page_output->addInlineJsVars(array('var Chora' => array('ANNOTATE_URL' => (string) Horde::url('annotate.php', true)->add(array('actionID' => 'log', 'rt' => $sourceroot, 'f' => $where, 'rev' => '')), 'loading_text' => _("Loading..."))));
Chora::header($title);
echo Chora::getFileViews($where, $rev)->render('annotate');
require CHORA_TEMPLATES . '/annotate/header.inc';
$author = '';
$style = 0;
while (list(, $line) = each($lines)) {
    $lineno = $line['lineno'];
    $author = Chora::showAuthorName($line['author']);
    $prevRev = $rev;
    $rev = $line['rev'];
    if ($prevRev != $rev) {
        $style = ++$style % 2;
    }
    $prev = $fl->getPreviousRevision($rev);
    $line = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($line['line'], 'space2html', array('encode' => true, 'encode_all' => true));
    include CHORA_TEMPLATES . '/annotate/line.inc';
}
require CHORA_TEMPLATES . '/annotate/footer.inc';
$page_output->footer();
Exemple #3
0
        }
        /* Otherwise, this cell has content; determine what it is */
        $rev = $row[$i];
        if (VC_Revision::valid($rev) && VC_Revision::sizeof($rev) % 2) {
            /* This is a branch point, so put the info out */
            $bg = isset($branchColours[$rev]) ? $branchColours[$rev] : 'white';
            $symname = $fl->branches[$rev];
            require CHORA_TEMPLATES . '/history/branch_cell.inc';
        } elseif (preg_match('|^:|', $rev)) {
            /* This is a continuation cell, so render it with the branch colour */
            $bgbr = VC_Revision::strip(preg_replace('|^\\:|', '', $rev), 1);
            $bg = isset($branchColours[$bgbr]) ? $branchColours[$bgbr] : 'white';
            require CHORA_TEMPLATES . '/history/blank.inc';
        } elseif (VC_Revision::valid($rev)) {
            /* This cell contains a revision, so render it */
            $bgbr = VC_Revision::strip($rev, 1);
            $bg = isset($branchColours[$bgbr]) ? $branchColours[$bgbr] : 'white';
            $log = $fl->logs[$rev];
            $author = Chora::showAuthorName($log->queryAuthor());
            $date = strftime('%e %b %Y', $log->queryDate());
            $lines = $log->queryChangedLines();
            require CHORA_TEMPLATES . '/history/rev.inc';
        } else {
            /* Exhausted other possibilities, just show a blank cell */
            require CHORA_TEMPLATES . '/history/blank.inc';
        }
    }
    require CHORA_TEMPLATES . '/history/row_end.inc';
}
require CHORA_TEMPLATES . '/history/footer.inc';
require $registry->getParam('templates', 'horde') . '/common-footer.inc';
Exemple #4
0
/**
 * Stats script.
 *
 * Copyright 2000-2015 Horde LLC (http://www.horde.org/)
 *
 * See the enclosed file COPYING for license information (GPL). If you
 * did not receive this file, see http://www.horde.org/licenses/gpl.
 *
 * @author  Anil Madhavapeddy <*****@*****.**>
 * @package Chora
 */
require_once __DIR__ . '/lib/Application.php';
Horde_Registry::appInit('chora');
/* Spawn the file object. */
try {
    $fl = $VC->getFile($where);
} catch (Horde_Vcs_Exception $e) {
    Chora::fatal($e);
}
$stats = array();
foreach ($fl->getLog() as $lg) {
    $qa = $lg->getAuthor();
    $stats[$qa] = isset($stats[$qa]) ? $stats[$qa] + 1 : 1;
}
arsort($stats);
$title = _("Statistics for:");
$page_output->addScriptFile('tables.js', 'horde');
Chora::header($title);
echo Chora::getHistoryViews($where)->render('stats');
require CHORA_TEMPLATES . '/stats/stats.inc';
$page_output->footer();
Exemple #5
0
$title = _("Logs for:");
$logs = $fl->getLog();
$first = end($logs);
$diffValueLeft = $first->getRevision();
$diffValueRight = $fl->getRevision();
$sel = '';
foreach ($fl->getTags() as $sm => $rv) {
    $sel .= '<option value="' . $rv . '">' . $sm . '</option>';
}
$branches = array();
if ($VC->hasFeature('branches')) {
    $branches = $fl->getBranches();
}
$page_output->addScriptFile('revlog.js');
Chora::header($title);
echo Chora::getHistoryViews($where)->render('browsefile');
require CHORA_TEMPLATES . '/log/header.inc';
$view = $injector->createInstance('Horde_View');
$currentDay = null;
echo '<div class="commit-list">';
reset($logs);
foreach ($logs as $log) {
    $day = date('Y-m-d', $log->getDate());
    if ($day != $currentDay) {
        echo '<h3>' . $day . '</h3>';
        $currentDay = $day;
    }
    echo $view->renderPartial('app/views/logMessage', array('object' => $log->toHash()));
}
echo '</div>';
$page_output->footer();
Exemple #6
0
        $realname = $currFile->getFileName();
        $mimeType = Horde_Mime_Magic::filenameToMIME($realname);
        $currFile->mimeType = $mimeType;
        if (Horde_String::lower(Horde_String::substr($realname, 0, 6)) == 'readme') {
            $readmes[] = $currFile;
        }
        $icon = $injector->getInstance('Horde_Core_Factory_MimeViewer')->getIcon($mimeType);
        $author = Chora::showAuthorName($lg->getAuthor());
        $filerev = $lg->getRevision();
        $date = $lg->getDate();
        $log = $lg->getMessage();
        $attic = $currFile->isDeleted();
        $fileName = $where . ($attic ? '/' . 'Attic' : '') . '/' . $realname;
        $name = $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($realname, 'space2html', array('encode' => true, 'encode_all' => true));
        $url = Chora::url('browsefile', $fileName, $branchArgs);
        $readableDate = Chora::readableTime($date);
        if ($log) {
            $shortLog = Horde_String::truncate(str_replace("\n", ' ', trim($log)), $conf['options']['shortLogLength']);
        }
        require CHORA_TEMPLATES . '/directory/file.inc';
    }
    echo '</tbody>';
}
echo '</table>';
if ($readmes) {
    $readmeCollection = new Chora_Readme_Collection($readmes);
    $readmeFile = $readmeCollection->chooseReadme();
    $readmeRenderer = new Chora_Renderer_File_Html($injector->createInstance('Horde_View'), $readmeFile, $readmeFile->getRevision());
    echo $readmeRenderer->render();
}
$page_output->footer();
Exemple #7
0
<div class="diff"<?php 
if ($id) {
    echo ' id="' . $id . '"';
}
?>
>
 <div class="diff-header"><h4><a href="<?php 
echo Chora::url('co', $file->getSourcerootPath(), array('onb' => $r1));
?>
"><?php 
echo $file->getSourcerootPath();
?>
</a></h4></div>
 <div class="diff-container diff-subheader">
  <div class="diff-left"><?php 
echo $this->escape($r1);
?>
</div>
  <div class="diff-right"><?php 
echo $this->escape($r2);
?>
</div>
 </div>

 <div class="diff-container">
  <div class="diff-left">
   <div class="diff-linenumbers">
    <ol>
    <?php 
foreach ($leftNumbers as $ln) {
    ?>
Exemple #8
0
 /**
  * Return formatted date information.
  *
  * @param integer $date  Number of seconds since epoch we wish to display.
  *
  * @return string  The date formatted pursuant to Horde prefs.
  */
 public static function formatDate($date)
 {
     if (!isset(self::$fdcache)) {
         self::$fdcache = $GLOBALS['prefs']->getValue('date_format') . ($GLOBALS['prefs']->getValue('twenty_four') ? ' %H:%M' : ' %I:%M %p');
     }
     return strftime(self::$fdcache, $date);
 }
Exemple #9
0
        }
    } else {
        foreach ($args as $key => $val) {
            $argstr .= "-{$key} '{$val}' ";
        }
    }
    header('Content-Type: image/png');
    passthru($conf['paths']['cvsgraph'] . ' ' . $argstr . ' ' . $file);
    exit;
}
// Display the wrapper page for the image.
$title = _("Graph for:");
Chora::header($title);
echo Chora::getHistoryViews($where)->render('cvsgraph');
$imgUrl = Chora::url('cvsgraph', $where, array('show_image' => 1));
$args = array('c' => $conf['paths']['cvsgraph_conf'], 'M' => 'graphMap', 'r' => $root, '0' => '&amp;', '1' => Chora::url('browsefile', $where, array('dummy' => 'true')), '2' => Chora::url('diff', $where, array('dummy' => 'true')), '3' => Chora::url('co', $where, array('dummy' => 'true')));
// Build up the argument string.
$argstr = '';
if (!strncasecmp(PHP_OS, 'WIN', 3)) {
    foreach ($args as $key => $val) {
        $argstr .= "-{$key} \"{$val}\" ";
    }
} else {
    foreach ($args as $key => $val) {
        $argstr .= "-{$key} '{$val}' ";
    }
}
// Generate the imagemap.
$map = shell_exec($conf['paths']['cvsgraph'] . ' ' . $argstr . ' -i ' . $file);
require CHORA_TEMPLATES . '/cvsgraph/cvsgraph.inc';
$page_output->footer();
Exemple #10
0
// Load the Horde Framework core, and set up inclusion paths.
require_once HORDE_BASE . '/lib/core.php';
// Registry
$registry =& Registry::singleton();
if (is_a($pushed = $registry->pushApp('chora', !defined('AUTH_HANDLER')), 'PEAR_Error')) {
    if ($pushed->getCode() == 'permission_denied') {
        Horde::authenticationFailureRedirect();
    }
    Horde::fatal($pushed, __FILE__, __LINE__, false);
}
$conf =& $GLOBALS['conf'];
@define('CHORA_TEMPLATES', $registry->getParam('templates'));
// Notification system.
$notification =& Notification::singleton();
$notification->attach('status');
// Find the base file path of Chora.
@define('CHORA_BASE', dirname(__FILE__) . '/..');
// Horde base libraries.
require_once HORDE_LIBS . 'Horde/Text.php';
require_once HORDE_LIBS . 'Horde/Help.php';
// Chora libraries and config.
require_once CHORA_BASE . '/config/sourceroots.php';
require_once CHORA_BASE . '/lib/Chora.php';
require_once HORDE_LIBS . 'Horde/VC.php';
// Initialize objects, path, etc.
Chora::init();
if (Chora::isRestricted($where)) {
    Chora::fatal('403 Forbidden', "{$where}: Forbidden by server configuration");
}
/* Start compression, if requested. */
Horde::compressOutput();
Exemple #11
0
 * @package Chora
 */
require_once __DIR__ . '/lib/Application.php';
// Cache the commit output for a week - it can be longer, since it should never
// change.
session_cache_expire(10080);
Horde_Registry::appInit('chora', array('session_cache_limiter' => 'public'));
// Exit if patchset feature is not available.
if (!$GLOBALS['VC']->hasFeature('patchsets')) {
    Chora::url('browsedir', $where)->redirect();
}
if (!($commit_id = Horde_Util::getFormData('commit'))) {
    Chora::fatal(_("No commit ID given"));
}
$title = sprintf(_("Commit %s"), $commit_id);
try {
    $ps = $VC->getPatchset(array('range' => array($commit_id), 'timezone' => $prefs->getValue('timezone')));
    $patchsets = $ps->getPatchsets();
} catch (Horde_Vcs_Exception $e) {
    Chora::fatal($e);
}
if (empty($patchsets)) {
    Chora::fatal(_("Commit Not Found"), '404 Not Found');
}
reset($patchsets);
$patchset = current($patchsets);
$page_output->addScriptFile('tables.js', 'horde');
$commit_page = 1;
Chora::header($title);
require CHORA_TEMPLATES . '/patchsets/ps_single.inc';
$page_output->footer();
Exemple #12
0
    }
    ?>
 </div>
<?php 
}
?>

 <div class="commit-message"><?php 
echo Chora::formatLogMessage($logMessage['log']);
?>
</div>

 <div class="commit-author">
  <div class="commit-author-avatar">
   <img src="http://www.gravatar.com/avatar/<?php 
echo md5(strtolower(trim(Chora::getAuthorEmail($logMessage['author']))));
?>
?d=mm&amp;s=40" />
  </div>
  <?php 
echo Chora::showAuthorName($logMessage['author'], true);
?>
<br />
  <?php 
echo Chora::formatDate($logMessage['date']);
?>
 </div>

 <div class="clear">&nbsp;</div>
</div>
Exemple #13
0
        $rendered = '<div class="fixed">' . $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($data['data'], 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO)) . '</div>';
    } elseif (strpos($mime_type, 'image/') !== false) {
        $rendered = Horde::img(Horde::selfUrl(true)->add('p', 1), '', '', '');
    } elseif ($pretty->canRender('inline')) {
        $data = $pretty->render('inline');
        $data = reset($data);
        $rendered = $data['data'];
    } else {
        $rendered = Horde::link(Horde::selfUrl(true)->add('p', 1)) . Horde::img('download.png') . ' ' . sprintf(_("Download revision %s"), $r) . '</a>';
    }
    /* Get this revision's attributes in printable form. */
    $log = $file->getLog($r);
    $title = sprintf(_("Revision %s (%s ago) for:"), $r, Chora::readableTime($log->getDate(), true));
    $page_output->addScriptFile('stripe.js', 'horde');
    Chora::header($title);
    echo Chora::getFileViews($where, $r)->render('co');
    require CHORA_TEMPLATES . '/checkout/checkout.inc';
    $page_output->footer();
    exit;
}
/* Download the file. */
// Get data.
$content = '';
while ($line = fgets($checkOut)) {
    $content .= $line;
}
fclose($checkOut);
// Get name.
$filename = $file->getFileName();
if ($browser->getBrowser() == 'opera') {
    $filename = strtr($filename, ' ', '_');
Exemple #14
0
     break;
 case 'unified':
 default:
     if ($ty != 'h') {
         /* Not Human-Readable format. */
         header('Content-Type: text/plain');
         echo implode("\n", $VC->getDiff($fl, $r1, $r2, $type, $num, $ws));
     } else {
         /* Human-Readable diff. */
         /* Output standard header information for the page. */
         $filename = preg_replace('/^.*\\//', '', $where);
         $pathname = preg_replace('/[^\\/]*$/', '', $where);
         $log = $fl->logs[$r2];
         $log_print = Chora::formatLogMessage($log->queryLog());
         require CHORA_TEMPLATES . '/common-header.inc';
         Chora::menu();
         require CHORA_TEMPLATES . '/headerbar.inc';
         require CHORA_TEMPLATES . '/diff/hr/header.inc';
         /* Retrieve the tree of changes. */
         $lns = VC_Diff::humanReadable($VC->getDiff($fl, $r1, $r2, 'unified', $num, $ws));
         /* TODO: check for errors here (PEAR_Error returned) - avsm */
         /* Is the diff empty? */
         if (!sizeof($lns)) {
             require CHORA_TEMPLATES . '/diff/hr/nochange.inc';
         } else {
             /* Iterate through every header block of changes */
             foreach ($lns as $header) {
                 $lefthead = Text::htmlspaces(@$header['oldline']);
                 $righthead = Text::htmlspaces(@$header['newline']);
                 $headfunc = Text::htmlspaces(@$header['function']);
                 require CHORA_TEMPLATES . '/diff/hr/row.inc';
Exemple #15
0
    if (!isset($title)) {
        $title = _("Commits to:");
    }
}
try {
    $ps = $VC->getPatchset($ps_opts);
    $patchsets = $ps->getPatchsets();
} catch (Horde_Vcs_Exception $e) {
    Chora::fatal($e);
}
if (empty($patchsets)) {
    Chora::fatal(_("Commit Not Found"), '404 Not Found');
}
$page_output->addScriptFile('tables.js', 'horde');
$page_output->addScriptFile('quickfinder.js', 'horde');
Chora::header($title);
echo Chora::getHistoryViews($where)->render('patchsets');
require CHORA_TEMPLATES . '/patchsets/header_table.inc';
$diff_img = Horde::img('diff.png', _("Diff"));
reset($patchsets);
while (list($id, $patchset) = each($patchsets)) {
    $patchset_link = Chora::url('commit', $where, array('commit' => $id))->link(array('title' => $id)) . htmlspecialchars($VC->abbrev($id)) . '</a>';
    $commitDate = Chora::formatDate($patchset['date']);
    $readableDate = Chora::readableTime($patchset['date'], true);
    $author = Chora::showAuthorName($patchset['author'], true);
    $logMessage = Chora::formatLogMessage($patchset['log']);
    $tags = array_merge($patchset['branch'], $patchset['tags']);
    require CHORA_TEMPLATES . '/patchsets/ps.inc';
}
require CHORA_TEMPLATES . '/patchsets/footer.inc';
$page_output->footer();
Exemple #16
0
    echo implode("\n", $VC->diff($fl, $vars->r1, $vars->r2, array('num' => $num, 'type' => $type))) . "\n";
    exit;
}
/* Human-Readable diff. */
$abbrev_r1 = $VC->abbrev($vars->r1);
$abbrev_r2 = $VC->abbrev($vars->r2);
$title = sprintf(_("Diff for %s between version %s and %s"), $injector->getInstance('Horde_Core_Factory_TextFilter')->filter($where, 'space2html', array('encode' => true, 'encode_all' => true)), $abbrev_r1, $abbrev_r2);
/* Format log entries. */
$log_messages = array();
foreach ($VC->getRevisionRange($fl, $vars->r1, $vars->r2) as $val) {
    $clog = $fl->getLog($val);
    if (!is_null($clog)) {
        $log_messages[] = $clog;
    }
}
$page_output->addScriptFile('stripe.js', 'horde');
Chora::header($title);
require CHORA_TEMPLATES . '/diff/header.inc';
$mime_type = Horde_Mime_Magic::filenameToMIME($fullname);
if (substr($mime_type, 0, 6) == 'image/') {
    /* Check for images. */
    $url1 = Chora::url('co', $where, array('r' => $vars->r1, 'p' => 1));
    $url2 = Chora::url('co', $where, array('r' => $vars->r2, 'p' => 1));
    echo "<tr><td><img src=\"{$url1}\" alt=\"" . htmlspecialchars($vars->r1) . '" /></td>' . "<td><img src=\"{$url2}\" alt=\"" . htmlspecialchars($vars->r2) . '" /></td></tr>';
} else {
    $view = $injector->createInstance('Horde_View');
    $view->addHelper('Chora_Diff_Helper');
    echo $view->diff($fl, $vars->r1, $vars->r2);
    echo $view->diffCaption();
}
$page_output->footer();
Exemple #17
0
            // Not supported in any other VC systems yet.
            $allDiffsLink = '';
        }
        $files = array();
        $dir = dirname($where);
        foreach ($patchset['members'] as $member) {
            $file = array();
            $mywhere = is_a($VC, 'VC_svn') ? $member['file'] : $dir . DIRECTORY_SEPARATOR . $member['file'];
            $file['file'] = Horde::link(Chora::url('patchsets', $mywhere), $member['file']) . $member['file'] . '</a>';
            if ($member['from'] == 'INITIAL') {
                $file['from'] = '<i>' . _("New File") . '</i>';
                $file['diff'] = '';
            } else {
                $file['from'] = Horde::link(Chora::url('co', $mywhere, array('r' => $member['from'])), $member['from']) . $member['from'] . '</a>';
                $file['diff'] = Horde::link(Chora::url('diff', $mywhere, array('r1' => $member['from'], 'r2' => $member['to'], 'ty' => 'u')), _("Diff")) . '(' . _("Diff") . ')';
            }
            if (substr($member['to'], -6) == '(DEAD)') {
                $file['to'] = '<i>' . _("Deleted") . '</i>';
                $file['diff'] = '';
            } else {
                $file['to'] = Horde::link(Chora::url('co', $mywhere, array('r' => $member['to'])), $member['to']) . $member['to'] . '</a>';
            }
            $files[] = $file;
        }
        $logMessage = Chora::formatLogMessage($patchset['log']);
        require CHORA_TEMPLATES . '/patchsets/ps.inc';
    }
    require $registry->getParam('templates', 'horde') . '/common-footer.inc';
} else {
    Chora::fatal('404 Not Found', "{$where}: no such file or directory");
}
Exemple #18
0
 /**
  */
 public function topbarCreate(Horde_Tree_Renderer_Base $tree, $parent = null, array $params = array())
 {
     $sourceroots = Chora::sourceroots();
     asort($sourceroots);
     foreach ($sourceroots as $key => $val) {
         $tree->addNode(array('id' => $parent . $key, 'parent' => $parent, 'label' => $val['name'], 'expanded' => false, 'params' => array('icon' => Horde_Themes::img('tree/folder.png'), 'url' => Chora::url('browsedir', '', array('rt' => $key)))));
     }
 }
Exemple #19
0
        $rev = $row[$i];
        //        if ($VC->isValidRevision($rev) && ($VC->sizeof($rev) % 2)) {
        if ($VC->isValidRevision($rev)) {
            /* This is a branch point, so put the info out. */
            $bg = isset($branch_colors[$rev]) ? $branch_colors[$rev] : '#e9e9e9';
            $symname = $fl->branches[$rev];
            require CHORA_TEMPLATES . '/history/branch_cell.inc';
        } elseif (preg_match('|^:|', $rev)) {
            /* This is a continuation cell, so render it with the
             * branch colour. */
            //            $bgbr = $VC->strip(preg_replace('|^\:|', '', $rev), 1);
            $bg = isset($branch_colors[$bgbr]) ? $branch_colors[$bgbr] : '#e9e9e9';
            require CHORA_TEMPLATES . '/history/blank.inc';
        } elseif ($VC->isValidRevision($rev)) {
            /* This cell contains a revision, so render it. */
            //            $bgbr = $VC->strip($rev, 1);
            $bg = isset($branch_colors[$bgbr]) ? $branch_colors[$bgbr] : '#e9e9e9';
            $log = $fl->getLog($rev);
            $author = Chora::showAuthorName($log->getAuthor());
            $date = strftime('%e %b %Y', $log->getDate());
            $lines = $log->getChanges();
            require CHORA_TEMPLATES . '/history/rev.inc';
        } else {
            /* Exhausted other possibilities, just show a blank cell. */
            require CHORA_TEMPLATES . '/history/blank.inc';
        }
    }
    echo '</tr>';
}
require CHORA_TEMPLATES . '/history/footer.inc';
$page_output->footer();
Exemple #20
0
 function getFileViews()
 {
     global $where;
     $views = array();
     $current = $_SERVER['PHP_SELF'];
     if (!empty($_SERVER['PATH_INFO'])) {
         $current = str_replace($_SERVER['PATH_INFO'], '', $current);
     }
     $current = str_replace('.php', '', basename($current));
     $views[] = $current == 'cvs' ? '<i>' . _("Logs") . '</i>' : Horde::link(Chora::url('cvs', $where), _("Logs"), 'widget') . _("Logs") . '</a>';
     // Subversion supports patchsets natively
     if (!empty($GLOBALS['conf']['paths']['cvsps']) || is_a($GLOBALS['VC'], 'VC_svn')) {
         $views[] = $current == 'patchsets' ? '<i>' . _("Patchsets") . '</i>' : Horde::link(Chora::url('patchsets', $where), _("Patchsets"), 'widget') . _("Patchsets") . '</a>';
     }
     if (!is_a($GLOBALS['VC'], 'VC_svn')) {
         $views[] = $current == 'history' ? '<i>' . _("Branches") . '</i>' : Horde::link(Chora::url('history', $where), _("Branches"), 'widget') . _("Branches") . '</a>';
     }
     if (!empty($GLOBALS['conf']['paths']['cvsgraph']) && !is_a($GLOBALS['VC'], 'VC_svn')) {
         $views[] = $current == 'cvsgraph' ? '<i>' . _("Graph") . '</i>' : Horde::link(Chora::url('cvsgraph', $where), _("Graph"), 'widget') . _("Graph") . '</a>';
     }
     $views[] = $current == 'stats' ? '<i>' . _("Statistics") . '</i>' : Horde::link(Chora::url('stats', $where), _("Statistics"), 'widget') . _("Statistics") . '</a>';
     return _("View:") . ' ' . implode(' | ', $views);
 }