Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/mlx/gui/flight.py

    r675 r719  
    11
    22from mlx.gui.common import *
     3import mlx.gui.cef as cef
    34
    45import mlx.const as const
     
    1718import time
    1819import os
     20import tempfile
     21import threading
    1922
    2023#-----------------------------------------------------------------------------
     
    14251428#-----------------------------------------------------------------------------
    14261429
     1430class RoutePage(Page):
     1431    """The page containing the route and the flight level."""
     1432    def __init__(self, wizard):
     1433        """Construct the page."""
     1434        super(RoutePage, self).__init__(wizard, xstr("route_title"),
     1435                                        xstr("route_help"),
     1436                                        completedHelp = xstr("route_chelp"))
     1437
     1438        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
     1439                                  xscale = 0.0, yscale = 0.0)
     1440
     1441        mainBox = gtk.VBox()
     1442        alignment.add(mainBox)
     1443        self.setMainWidget(alignment)
     1444
     1445        levelBox = gtk.HBox()
     1446
     1447        label = gtk.Label(xstr("route_level"))
     1448        label.set_use_underline(True)
     1449        levelBox.pack_start(label, True, True, 0)
     1450
     1451        self._cruiseLevel = gtk.SpinButton()
     1452        self._cruiseLevel.set_increments(step = 10, page = 100)
     1453        self._cruiseLevel.set_range(min = 0, max = 500)
     1454        self._cruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
     1455        self._cruiseLevel.set_numeric(True)
     1456        self._cruiseLevel.connect("changed", self._cruiseLevelChanged)
     1457        self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
     1458        label.set_mnemonic_widget(self._cruiseLevel)
     1459
     1460        levelBox.pack_start(self._cruiseLevel, False, False, 8)
     1461
     1462        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
     1463                                  xscale = 0.0, yscale = 0.0)
     1464        alignment.add(levelBox)
     1465
     1466        mainBox.pack_start(alignment, False, False, 0)
     1467
     1468
     1469        routeBox = gtk.VBox()
     1470
     1471        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
     1472                                  xscale = 0.0, yscale = 0.0)
     1473        label = gtk.Label(xstr("route_route"))
     1474        label.set_use_underline(True)
     1475        alignment.add(label)
     1476        routeBox.pack_start(alignment, True, True, 0)
     1477
     1478        routeWindow = gtk.ScrolledWindow()
     1479        routeWindow.set_size_request(400, 80)
     1480        routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
     1481                                    else gtk.SHADOW_IN)
     1482        routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
     1483                               else gtk.POLICY_AUTOMATIC,
     1484                               gtk.PolicyType.AUTOMATIC if pygobject
     1485                               else gtk.POLICY_AUTOMATIC)
     1486
     1487        self._uppercasingRoute = False
     1488
     1489        self._route = gtk.TextView()
     1490        self._route.set_tooltip_text(xstr("route_route_tooltip"))
     1491        self._route.set_wrap_mode(WRAP_WORD)
     1492        self._route.get_buffer().connect("changed", self._routeChanged)
     1493        self._route.get_buffer().connect_after("insert-text", self._routeInserted)
     1494        routeWindow.add(self._route)
     1495
     1496        label.set_mnemonic_widget(self._route)
     1497        routeBox.pack_start(routeWindow, True, True, 0)
     1498
     1499        mainBox.pack_start(routeBox, True, True, 8)
     1500
     1501        alternateBox = gtk.HBox()
     1502
     1503        label = gtk.Label(xstr("route_altn"))
     1504        label.set_use_underline(True)
     1505        alternateBox.pack_start(label, True, True, 0)
     1506
     1507        self._alternate = gtk.Entry()
     1508        self._alternate.set_width_chars(6)
     1509        self._alternate.connect("changed", self._alternateChanged)
     1510        self._alternate.set_tooltip_text(xstr("route_altn_tooltip"))
     1511        label.set_mnemonic_widget(self._alternate)
     1512
     1513        alternateBox.pack_start(self._alternate, False, False, 8)
     1514
     1515        alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
     1516                                  xscale = 0.0, yscale = 0.0)
     1517        alignment.add(alternateBox)
     1518
     1519        mainBox.pack_start(alignment, False, False, 0)
     1520
     1521        self.addCancelFlightButton()
     1522
     1523        self._backButton = self.addPreviousButton(clicked = self._backClicked)
     1524        self._button = self.addNextButton(clicked = self._forwardClicked)
     1525
     1526    @property
     1527    def filedCruiseLevel(self):
     1528        """Get the filed cruise level."""
     1529        return self._cruiseLevel.get_value_as_int()
     1530
     1531    @property
     1532    def route(self):
     1533        """Get the route."""
     1534        return self._getRoute()
     1535
     1536    @property
     1537    def alternate(self):
     1538        """Get the ICAO code of the alternate airport."""
     1539        return self._alternate.get_text()
     1540
     1541    def activate(self):
     1542        """Setup the route from the booked flight."""
     1543        self._cruiseLevel.set_value(0)
     1544        self._cruiseLevel.set_text("")
     1545        self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
     1546        self._alternate.set_text("")
     1547        self._updateForwardButton()
     1548
     1549    def _getRoute(self):
     1550        """Get the text of the route."""
     1551        buffer = self._route.get_buffer()
     1552        return buffer.get_text(buffer.get_start_iter(),
     1553                               buffer.get_end_iter(), True)
     1554
     1555    def _updateForwardButton(self):
     1556        """Update the sensitivity of the forward button."""
     1557        cruiseLevelText = self._cruiseLevel.get_text()
     1558        cruiseLevel = int(cruiseLevelText) if cruiseLevelText else 0
     1559        alternate = self._alternate.get_text()
     1560        self._button.set_sensitive(cruiseLevel>=50 and self._getRoute()!="" and
     1561                                   len(alternate)==4)
     1562
     1563    def _cruiseLevelChanged(self, *arg):
     1564        """Called when the cruise level has changed."""
     1565        self._updateForwardButton()
     1566
     1567    def _routeChanged(self, textBuffer):
     1568        """Called when the route has changed."""
     1569        if not self._uppercasingRoute:
     1570            self._updateForwardButton()
     1571
     1572    def _routeInserted(self, textBuffer, iter, text, length):
     1573        """Called when new characters are inserted into the route.
     1574
     1575        It uppercases all characters."""
     1576        if not self._uppercasingRoute:
     1577            self._uppercasingRoute = True
     1578
     1579            iter1 = iter.copy()
     1580            iter1.backward_chars(length)
     1581            textBuffer.delete(iter, iter1)
     1582
     1583            textBuffer.insert(iter, text.upper())
     1584
     1585            self._uppercasingRoute = False
     1586
     1587    def _alternateChanged(self, entry):
     1588        """Called when the alternate airport has changed."""
     1589        entry.set_text(entry.get_text().upper())
     1590        self._updateForwardButton()
     1591
     1592    def _backClicked(self, button):
     1593        """Called when the Back button is pressed."""
     1594        self.goBack()
     1595
     1596    def _forwardClicked(self, button):
     1597        """Called when the Forward button is clicked."""
     1598        if self._wizard.gui.flight.aircraft.simBriefData is None:
     1599            self._wizard.usingSimBrief = False
     1600        if self._wizard.gui.config.useSimBrief and \
     1601           self._wizard.usingSimBrief is not False:
     1602            self._wizard.nextPage()
     1603        else:
     1604            self._wizard.usingSimBrief = False
     1605            self._wizard.jumpPage(3)
     1606
     1607#-----------------------------------------------------------------------------
     1608
     1609class SimBriefCredentialsDialog(gtk.Dialog):
     1610    """A dialog window to ask for SimBrief credentials."""
     1611    def __init__(self, gui, userName, password, rememberPassword):
     1612        """Construct the dialog."""
     1613        super(SimBriefCredentialsDialog, self).__init__(WINDOW_TITLE_BASE + " - " +
     1614                                                        xstr("simbrief_credentials_title"),
     1615                                                        gui.mainWindow,
     1616                                                        DIALOG_MODAL)
     1617        self.add_button(xstr("button_cancel"), RESPONSETYPE_CANCEL)
     1618        self.add_button(xstr("button_ok"), RESPONSETYPE_OK)
     1619
     1620        contentArea = self.get_content_area()
     1621
     1622        contentAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
     1623                                         xscale = 0.0, yscale = 0.0)
     1624        contentAlignment.set_padding(padding_top = 4, padding_bottom = 16,
     1625                                     padding_left = 8, padding_right = 8)
     1626
     1627        contentArea.pack_start(contentAlignment, False, False, 0)
     1628
     1629        contentVBox = gtk.VBox()
     1630        contentAlignment.add(contentVBox)
     1631
     1632        label = gtk.Label(xstr("simbrief_login_failed"))
     1633        label.set_alignment(0.0, 0.0)
     1634
     1635        contentVBox.pack_start(label, False, False, 0)
     1636
     1637        tableAlignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
     1638                                       xscale = 0.0, yscale = 0.0)
     1639        tableAlignment.set_padding(padding_top = 24, padding_bottom = 0,
     1640                                   padding_left = 0, padding_right = 0)
     1641
     1642        table = gtk.Table(3, 2)
     1643        table.set_row_spacings(4)
     1644        table.set_col_spacings(16)
     1645        table.set_homogeneous(False)
     1646
     1647        tableAlignment.add(table)
     1648        contentVBox.pack_start(tableAlignment, True, True, 0)
     1649
     1650        label = gtk.Label(xstr("simbrief_username"))
     1651        label.set_use_underline(True)
     1652        label.set_alignment(0.0, 0.5)
     1653        table.attach(label, 0, 1, 0, 1)
     1654
     1655        self._userName = gtk.Entry()
     1656        self._userName.set_width_chars(16)
     1657        #self._userName.connect("changed",
     1658        #                       lambda button: self._updateForwardButton())
     1659        self._userName.set_tooltip_text(xstr("simbrief_username_tooltip"))
     1660        self._userName.set_text(userName)
     1661        table.attach(self._userName, 1, 2, 0, 1)
     1662        label.set_mnemonic_widget(self._userName)
     1663
     1664        label = gtk.Label(xstr("simbrief_password"))
     1665        label.set_use_underline(True)
     1666        label.set_alignment(0.0, 0.5)
     1667        table.attach(label, 0, 1, 1, 2)
     1668
     1669        self._password = gtk.Entry()
     1670        self._password.set_visibility(False)
     1671        #self._password.connect("changed",
     1672        #                       lambda button: self._updateForwardButton())
     1673        self._password.set_tooltip_text(xstr("simbrief_password_tooltip"))
     1674        self._password.set_text(password)
     1675        table.attach(self._password, 1, 2, 1, 2)
     1676        label.set_mnemonic_widget(self._password)
     1677
     1678        self._rememberButton = gtk.CheckButton(xstr("simbrief_remember_password"))
     1679        self._rememberButton.set_use_underline(True)
     1680        self._rememberButton.set_tooltip_text(xstr("simbrief_remember_tooltip"))
     1681        self._rememberButton.set_active(rememberPassword)
     1682        table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
     1683
     1684    @property
     1685    def userName(self):
     1686        """Get the user name entered."""
     1687        return self._userName.get_text()
     1688
     1689    @property
     1690    def password(self):
     1691        """Get the password entered."""
     1692        return self._password.get_text()
     1693
     1694    @property
     1695    def rememberPassword(self):
     1696        """Get whether the password is to be remembered."""
     1697        return self._rememberButton.get_active()
     1698
     1699    def run(self):
     1700        """Run the dialog."""
     1701        self.show_all()
     1702
     1703        response = super(SimBriefCredentialsDialog, self).run()
     1704
     1705        self.hide()
     1706
     1707        return response
     1708
     1709#-----------------------------------------------------------------------------
     1710
     1711class SimBriefSetupPage(Page):
     1712    """Page for setting up some parameters for SimBrief."""
     1713    monthNum2Name = [
     1714        "JAN",
     1715        "FEB",
     1716        "MAR",
     1717        "APR",
     1718        "MAY",
     1719        "JUN",
     1720        "JUL",
     1721        "AUG",
     1722        "SEP",
     1723        "OCT",
     1724        "NOV",
     1725        "DEC"
     1726        ]
     1727
     1728    progress2Message = {
     1729        cef.SIMBRIEF_PROGRESS_SEARCHING_BROWSER: "simbrief_progress_searching_browser",
     1730        cef.SIMBRIEF_PROGRESS_LOADING_FORM: "simbrief_progress_loading_form",
     1731        cef.SIMBRIEF_PROGRESS_FILLING_FORM: "simbrief_progress_filling_form",
     1732        cef.SIMBRIEF_PROGRESS_WAITING_LOGIN: "simbrief_progress_waiting_login",
     1733        cef.SIMBRIEF_PROGRESS_LOGGING_IN: "simbrief_progress_logging_in",
     1734        cef.SIMBRIEF_PROGRESS_WAITING_RESULT: "simbrief_progress_waiting_result",
     1735        cef.SIMBRIEF_PROGRESS_RETRIEVING_BRIEFING: "simbrief_progress_retrieving_briefing"
     1736        }
     1737
     1738    result2Message = {
     1739        cef.SIMBRIEF_RESULT_ERROR_OTHER: "simbrief_result_error_other",
     1740        cef.SIMBRIEF_RESULT_ERROR_NO_FORM: "simbrief_result_error_no_form",
     1741        cef.SIMBRIEF_RESULT_ERROR_NO_POPUP: "simbrief_result_error_no_popup",
     1742        cef.SIMBRIEF_RESULT_ERROR_LOGIN_FAILED: "simbrief_result_error_login_failed"
     1743        }
     1744
     1745    @staticmethod
     1746    def getHTMLFilePath():
     1747        """Get the path of the HTML file to contain the generated flight
     1748        plan."""
     1749        if os.name=="nt":
     1750            return os.path.join(tempfile.gettempdir(),
     1751                                "mlx_simbrief" +
     1752                                (".secondary" if secondaryInstallation else "") +
     1753                                ".html")
     1754        else:
     1755            import pwd
     1756            return os.path.join(tempfile.gettempdir(),
     1757                                "mlx_simbrief." + pwd.getpwuid(os.getuid())[0] + "" +
     1758                                (".secondary" if secondaryInstallation else "") +
     1759                                ".html")
     1760
     1761    def __init__(self, wizard):
     1762        """Construct the setup page."""
     1763
     1764        super(SimBriefSetupPage, self).__init__(wizard,
     1765                                                xstr("simbrief_setup_title"),
     1766                                                xstr("simbrief_setup_help"),
     1767                                                xstr("simbrief_setup_chelp"))
     1768
     1769        alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
     1770                                  xscale = 0.0, yscale = 0.0)
     1771
     1772        table = gtk.Table(9, 3)
     1773        table.set_row_spacings(4)
     1774        table.set_col_spacings(16)
     1775        table.set_homogeneous(False)
     1776        alignment.add(table)
     1777        self.setMainWidget(alignment)
     1778
     1779        label = gtk.Label(xstr("simbrief_username"))
     1780        label.set_use_underline(True)
     1781        label.set_alignment(0.0, 0.5)
     1782        table.attach(label, 0, 1, 0, 1)
     1783
     1784        self._userName = gtk.Entry()
     1785        self._userName.set_width_chars(16)
     1786        self._userName.connect("changed",
     1787                               lambda button: self._updateForwardButton())
     1788        self._userName.set_tooltip_text(xstr("simbrief_username_tooltip"))
     1789        table.attach(self._userName, 1, 2, 0, 1)
     1790        label.set_mnemonic_widget(self._userName)
     1791
     1792        label = gtk.Label(xstr("simbrief_password"))
     1793        label.set_use_underline(True)
     1794        label.set_alignment(0.0, 0.5)
     1795        table.attach(label, 0, 1, 1, 2)
     1796
     1797        self._password = gtk.Entry()
     1798        self._password.set_visibility(False)
     1799        self._password.connect("changed",
     1800                               lambda button: self._updateForwardButton())
     1801        self._password.set_tooltip_text(xstr("simbrief_password_tooltip"))
     1802        table.attach(self._password, 1, 2, 1, 2)
     1803        label.set_mnemonic_widget(self._password)
     1804
     1805        self._rememberButton = gtk.CheckButton(xstr("simbrief_remember_password"))
     1806        self._rememberButton.set_use_underline(True)
     1807        self._rememberButton.set_tooltip_text(xstr("simbrief_remember_tooltip"))
     1808        table.attach(self._rememberButton, 1, 2, 2, 3, ypadding = 8)
     1809
     1810        self._credentialsCondition = threading.Condition()
     1811        self._credentialsAvailable = False
     1812        self._credentialsUserName = None
     1813        self._credentialsPassword = None
     1814
     1815        label = gtk.Label(xstr("simbrief_extra_fuel"))
     1816        label.set_use_underline(True)
     1817        label.set_alignment(0.0, 0.5)
     1818        table.attach(label, 0, 1, 3, 4)
     1819
     1820        self._extraFuel = IntegerEntry(defaultValue = 0)
     1821        self._extraFuel.set_width_chars(6)
     1822        self._extraFuel.set_tooltip_text(xstr("simbrief_extra_fuel_tooltip"))
     1823        table.attach(self._extraFuel, 1, 2, 3, 4)
     1824        label.set_mnemonic_widget(self._extraFuel)
     1825
     1826        table.attach(gtk.Label("kg"), 2, 3, 3, 4)
     1827
     1828        label = gtk.Label(xstr("simbrief_takeoff_runway"))
     1829        label.set_use_underline(True)
     1830        label.set_alignment(0.0, 0.5)
     1831        table.attach(label, 0, 1, 4, 5)
     1832
     1833        self._takeoffRunway = gtk.Entry()
     1834        self._takeoffRunway.set_width_chars(10)
     1835        self._takeoffRunway.set_tooltip_text(xstr("simbrief_takeoff_runway_tooltip"))
     1836        self._takeoffRunway.connect("changed", self._upperChanged)
     1837        table.attach(self._takeoffRunway, 1, 2, 4, 5)
     1838        label.set_mnemonic_widget(self._takeoffRunway)
     1839
     1840        label = gtk.Label(xstr("simbrief_landing_runway"))
     1841        label.set_use_underline(True)
     1842        label.set_alignment(0.0, 0.5)
     1843        table.attach(label, 0, 1, 5, 6)
     1844
     1845        self._landingRunway = gtk.Entry()
     1846        self._landingRunway.set_width_chars(10)
     1847        self._landingRunway.set_tooltip_text(xstr("simbrief_takeoff_runway_tooltip"))
     1848        self._landingRunway.connect("changed", self._upperChanged)
     1849        table.attach(self._landingRunway, 1, 2, 5, 6)
     1850        label.set_mnemonic_widget(self._landingRunway)
     1851
     1852        label = gtk.Label(xstr("simbrief_climb_profile"))
     1853        label.set_use_underline(True)
     1854        label.set_alignment(0.0, 0.5)
     1855        table.attach(label, 0, 1, 6, 7)
     1856
     1857        self._climbProfile = gtk.ComboBox()
     1858        renderer = gtk.CellRendererText()
     1859        self._climbProfile.pack_start(renderer, True)
     1860        self._climbProfile.add_attribute(renderer, "text", 0)
     1861        self._climbProfile.set_tooltip_text(xstr("simbrief_climb_profile_tooltip"))
     1862        table.attach(self._climbProfile, 1, 2, 6, 7)
     1863        label.set_mnemonic_widget(self._climbProfile)
     1864
     1865        label = gtk.Label(xstr("simbrief_cruise_profile"))
     1866        label.set_use_underline(True)
     1867        label.set_alignment(0.0, 0.5)
     1868        table.attach(label, 0, 1, 7, 8)
     1869
     1870        self._cruiseProfile = gtk.ComboBox()
     1871        renderer = gtk.CellRendererText()
     1872        self._cruiseProfile.pack_start(renderer, True)
     1873        self._cruiseProfile.add_attribute(renderer, "text", 0)
     1874        self._cruiseProfile.set_tooltip_text(xstr("simbrief_cruise_profile_tooltip"))
     1875        table.attach(self._cruiseProfile, 1, 2, 7, 8)
     1876        label.set_mnemonic_widget(self._cruiseProfile)
     1877
     1878        label = gtk.Label(xstr("simbrief_descent_profile"))
     1879        label.set_use_underline(True)
     1880        label.set_alignment(0.0, 0.5)
     1881        table.attach(label, 0, 1, 8, 9)
     1882
     1883        self._descentProfile = gtk.ComboBox()
     1884        renderer = gtk.CellRendererText()
     1885        self._descentProfile.pack_start(renderer, True)
     1886        self._descentProfile.add_attribute(renderer, "text", 0)
     1887        self._descentProfile.set_tooltip_text(xstr("simbrief_descent_profile_tooltip"))
     1888        table.attach(self._descentProfile, 1, 2, 8, 9)
     1889        label.set_mnemonic_widget(self._descentProfile)
     1890
     1891        self.addCancelFlightButton()
     1892
     1893        self._backButton = self.addPreviousButton(clicked = self._backClicked)
     1894        self._button = self.addNextButton(clicked = self._forwardClicked)
     1895
     1896    def activate(self):
     1897        """Activate the SimBrief setup page"""
     1898        config = self._wizard.gui.config
     1899
     1900        self._userName.set_text(config.simBriefUserName)
     1901        self._userName.set_sensitive(True)
     1902
     1903        self._password.set_text(config.simBriefPassword)
     1904        self._password.set_sensitive(True)
     1905
     1906        self._rememberButton.set_active(config.rememberSimBriefPassword)
     1907        self._rememberButton.set_sensitive(True)
     1908
     1909        self._extraFuel.set_int(0)
     1910        self._extraFuel.set_sensitive(True)
     1911
     1912        self._takeoffRunway.set_text("")
     1913        self._takeoffRunway.set_sensitive(True)
     1914
     1915        self._landingRunway.set_text("")
     1916        self._landingRunway.set_sensitive(True)
     1917
     1918        simBriefData = self._wizard.gui.flight.aircraft.simBriefData
     1919        for (control, profiles) in [(self._climbProfile,
     1920                                     simBriefData.climbProfiles),
     1921                                    (self._cruiseProfile,
     1922                                     simBriefData.cruiseProfiles),
     1923                                    (self._descentProfile,
     1924                                     simBriefData.descentProfiles)]:
     1925            model = gtk.ListStore(str)
     1926            for profile in profiles:
     1927                model.append([profile])
     1928            control.set_model(model)
     1929            control.set_sensitive(True)
     1930
     1931        self._climbProfile.set_active(0)
     1932        self._cruiseProfile.set_active(0)
     1933        self._descentProfile.set_active(0)
     1934
     1935        self._updateForwardButton()
     1936
     1937    def _updateForwardButton(self):
     1938        """Update the sensitivity of the forward button."""
     1939        self._button.set_sensitive(len(self._userName.get_text())>0 and
     1940                                   len(self._password.get_text())>0)
     1941
     1942    def _backClicked(self, button):
     1943        """Called when the Back button is pressed."""
     1944        self.goBack()
     1945
     1946    def _forwardClicked(self, button):
     1947        if self._completed:
     1948            self._wizard.nextPage()
     1949        else:
     1950            config = self._wizard.gui.config
     1951
     1952            config.simBriefUserName = self._userName.get_text()
     1953
     1954            rememberPassword = self._rememberButton.get_active()
     1955            config.simBriefPassword = \
     1956              self._password.get_text() if rememberPassword else ""
     1957            config.rememberSimBriefPassword = rememberPassword
     1958
     1959            config.save()
     1960
     1961            plan = self._getPlan()
     1962            print "plan:", plan
     1963
     1964            takeoffRunway = self._takeoffRunway.get_text()
     1965            if takeoffRunway:
     1966                self._wizard.takeoffRunway = takeoffRunway
     1967
     1968            landingRunway = self._landingRunway.get_text()
     1969            if landingRunway:
     1970                self._wizard.landingRunway = landingRunway
     1971
     1972            self._userName.set_sensitive(False)
     1973            self._password.set_sensitive(False)
     1974            self._rememberButton.set_sensitive(False)
     1975            self._extraFuel.set_sensitive(False)
     1976            self._takeoffRunway.set_sensitive(False)
     1977            self._landingRunway.set_sensitive(False)
     1978
     1979            self._climbProfile.set_sensitive(False)
     1980            self._cruiseProfile.set_sensitive(False)
     1981            self._descentProfile.set_sensitive(False)
     1982
     1983            self._wizard.gui.beginBusy(xstr("simbrief_calling"))
     1984
     1985            cef.startFastTimeout()
     1986            cef.callSimBrief(plan,
     1987                             self._getCredentialsCallback,
     1988                             self._simBriefProgressCallback,
     1989                             SimBriefSetupPage.getHTMLFilePath())
     1990
     1991            startSound(const.SOUND_NOTAM)
     1992
     1993    def _getCredentialsCallback(self, count):
     1994        """Called when the SimBrief home page requests the credentials."""
     1995        with self._credentialsCondition:
     1996            self._credentialsAvailable = False
     1997
     1998            gobject.idle_add(self._getCredentials, count)
     1999
     2000            while not self._credentialsAvailable:
     2001                self._credentialsCondition.wait()
     2002
     2003            return (self._credentialsUserName, self._credentialsPassword)
     2004
     2005    def _getCredentials(self, count):
     2006        """Get the credentials.
     2007
     2008        If count is 0, the user name and password entered into the setup page
     2009        are returned. Otherwise a dialog box is displayed informing the user of
     2010        invalid credentials and requesting another set of them."""
     2011        with self._credentialsCondition:
     2012            if count==0:
     2013                self._credentialsUserName = self._userName.get_text()
     2014                self._credentialsPassword = self._password.get_text()
     2015            else:
     2016                gui = self._wizard.gui
     2017                config = gui.config
     2018
     2019                dialog = SimBriefCredentialsDialog(gui,
     2020                                                   config.simBriefUserName,
     2021                                                   config.simBriefPassword,
     2022                                                   config.rememberSimBriefPassword)
     2023                response = dialog.run()
     2024
     2025                if response==RESPONSETYPE_OK:
     2026                    self._credentialsUserName = dialog.userName
     2027                    self._userName.set_text(self._credentialsUserName)
     2028                    self._credentialsPassword = dialog.password
     2029                    self._password.set_text(self._credentialsPassword)
     2030                    rememberPassword = dialog.rememberPassword
     2031
     2032                    config.simBriefUserName = self._credentialsUserName
     2033
     2034                    config.simBriefPassword = \
     2035                        self._credentialsPassword if rememberPassword else ""
     2036                    config.rememberSimBriefPassword = rememberPassword
     2037
     2038                    config.save()
     2039                else:
     2040                    self._credentialsUserName = None
     2041                    self._credentialsPassword = None
     2042
     2043            self._credentialsAvailable = True
     2044            self._credentialsCondition.notify()
     2045
     2046    def _simBriefProgressCallback(self, progress, result, flightInfo):
     2047        """Called by the SimBrief handling thread."""
     2048        gobject.idle_add(self._simBriefProgress, progress, result, flightInfo)
     2049
     2050    def _simBriefProgress(self, progress, result, flightInfo):
     2051        """The real SimBrief progress handler."""
     2052        print "_simBriefProgress", progress, result, flightInfo
     2053        if result==cef.SIMBRIEF_RESULT_NONE:
     2054            message = SimBriefSetupPage.progress2Message.get(progress,
     2055                                                             "simbrief_progress_unknown")
     2056            self._wizard.gui.updateBusyState(xstr(message))
     2057        else:
     2058            cef.stopFastTimeout()
     2059            self._wizard.gui.endBusy()
     2060
     2061            if result==cef.SIMBRIEF_RESULT_OK:
     2062                self._wizard.departureMETARChanged(flightInfo["orig_metar"],
     2063                                                   self)
     2064                self._wizard.arrivalMETARChanged(flightInfo["dest_metar"], self)
     2065                self._wizard.nextPage()
     2066            else:
     2067                message = SimBriefSetupPage.result2Message.get(result,
     2068                                                               "simbrief_result_unknown")
     2069                dialog = gtk.MessageDialog(parent = self._wizard.gui.mainWindow,
     2070                                           type = MESSAGETYPE_ERROR,
     2071                                           message_format =
     2072                                           xstr(message) + "\n"+
     2073                                           xstr("simbrief_cancelled"))
     2074
     2075                dialog.add_button(xstr("button_ok"), RESPONSETYPE_OK)
     2076                dialog.set_title(WINDOW_TITLE_BASE)
     2077                secondary = xstr("flightsel_save_failed_sec")
     2078                dialog.format_secondary_markup(secondary)
     2079                dialog.run()
     2080                dialog.hide()
     2081
     2082                self._wizard.usingSimBrief = False
     2083                self._wizard.jumpPage(2, fromPageShift = 1)
     2084
     2085    def _getPlan(self):
     2086        """Get the flight plan data for SimBrief."""
     2087        plan = {
     2088            "airline": "MAH",
     2089            "selcal": "XXXX",
     2090            "fuelfactor": "P000",
     2091            "contpct": "0.05",
     2092            "resvrule": "45",
     2093            "taxiout": "10",
     2094            "taxiin": "10",
     2095            "civalue": "AUTO"
     2096            }
     2097
     2098        wizard = self._wizard
     2099        gui = wizard.gui
     2100
     2101        loginResult = wizard.loginResult
     2102        plan["cpt"] = loginResult.pilotName
     2103        plan["pid"] = loginResult.pilotID
     2104
     2105        bookedFlight = wizard.bookedFlight
     2106        plan["fltnum"] = wizard.bookedFlight.callsign[2:]
     2107        plan["type"] = const.icaoCodes[bookedFlight.aircraftType]
     2108        plan["orig"] = bookedFlight.departureICAO
     2109        plan["dest"] = bookedFlight.arrivalICAO
     2110        plan["reg"] = bookedFlight.tailNumber
     2111        plan["fin"] = bookedFlight.tailNumber[3:]
     2112        plan["pax"] = str(bookedFlight.numPassengers)
     2113
     2114        departureTime = bookedFlight.departureTime
     2115        plan["date"] = "%d%s%d" % (departureTime.day,
     2116                                   SimBriefSetupPage.monthNum2Name[departureTime.month-1],
     2117                                   departureTime.year%100)
     2118        plan["deph"] = str(departureTime.hour)
     2119        plan["depm"] = str(departureTime.minute)
     2120
     2121        arrivalTime = bookedFlight.arrivalTime
     2122        plan["steh"] = str(arrivalTime.hour)
     2123        plan["stem"] = str(arrivalTime.minute)
     2124
     2125        plan["manualzfw"] = str(wizard.zfw / 1000.0)
     2126        plan["cargo"] = str((wizard.bagWeight + wizard.cargoWeight + wizard.mailWeight)/1000.0)
     2127
     2128        plan["route"] = wizard.route
     2129        plan["fl"] = str(wizard.filedCruiseAltitude)
     2130        plan["altn"] = wizard.alternate
     2131
     2132        plan["addedfuel"] = str(self._extraFuel.get_int() / 1000.0)
     2133        plan["origrwy"] = self._takeoffRunway.get_text()
     2134        plan["destrwy"] = self._landingRunway.get_text()
     2135
     2136        for (key, control) in [("climb", self._climbProfile),
     2137                               ("cruise", self._cruiseProfile),
     2138                               ("descent", self._descentProfile)]:
     2139            model = control.get_model()
     2140            active = control.get_active_iter()
     2141            value = model.get_value(active, 0)
     2142            plan[key] = value
     2143
     2144        return plan
     2145
     2146    def _upperChanged(self, entry, arg = None):
     2147        """Called when the value of some entry widget has changed and the value
     2148        should be converted to uppercase."""
     2149        entry.set_text(entry.get_text().upper())
     2150
     2151#-----------------------------------------------------------------------------
     2152
     2153class SimBriefingPage(Page):
     2154    """Page to display the SimBrief HTML briefing."""
     2155    class BrowserLifeSpanHandler(object):
     2156        """The life-span handler of a browser."""
     2157        def __init__(self, simBriefingPage):
     2158            """Construct the life-span handler for the given page."""
     2159            self._simBriefingPage = simBriefingPage
     2160
     2161        def OnBeforeClose(self, browser):
     2162            """Called before closing the browser."""
     2163            self._simBriefingPage._invalidateBrowser()
     2164
     2165    def __init__(self, wizard):
     2166        """Construct the setup page."""
     2167
     2168        super(SimBriefingPage, self).__init__(wizard,
     2169                                              "SimBrief flight plan", "")
     2170
     2171        self._alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
     2172                                       xscale = 1.0, yscale = 1.0)
     2173
     2174        self._container = cef.getContainer()
     2175        self._alignment.add(self._container)
     2176
     2177        self.setMainWidget(self._alignment)
     2178
     2179        self._browser = None
     2180
     2181        self.addCancelFlightButton()
     2182
     2183        self.addPreviousButton(clicked = self._backClicked)
     2184
     2185        self._button = self.addNextButton(clicked = self._forwardClicked)
     2186        self._button.set_label(xstr("briefing_button"))
     2187        self._button.set_has_tooltip(False)
     2188        self._button.set_use_stock(False)
     2189
     2190    def activate(self):
     2191        """Activate the SimBrief flight plan page"""
     2192        if self._browser is None:
     2193            self._startBrowser()
     2194        else:
     2195            self._browser.Reload()
     2196
     2197    def grabDefault(self):
     2198        """If the page has a default button, make it the default one."""
     2199        super(SimBriefingPage, self).grabDefault()
     2200
     2201        if self._browser is None:
     2202            self._startBrowser()
     2203
     2204    def _backClicked(self, button):
     2205        """Called when the Back button has been pressed."""
     2206        self.goBack()
     2207
     2208    def _forwardClicked(self, button):
     2209        """Called when the Forward button has been pressed."""
     2210        if not self._completed:
     2211            self._button.set_label(xstr("button_next"))
     2212            self._button.set_tooltip_text(xstr("button_next_tooltip"))
     2213            self._wizard.usingSimBrief = True
     2214            self.complete()
     2215
     2216        self._wizard.nextPage()
     2217
     2218    def _startBrowser(self):
     2219        """Start the browser.
     2220
     2221        If a container is needed, create one."""
     2222        if self._container is None:
     2223            self._container = cef.getContainer()
     2224            self._alignment.add(self._container)
     2225
     2226        url = "file://" + SimBriefSetupPage.getHTMLFilePath()
     2227        self._browser = cef.startInContainer(self._container, url)
     2228
     2229        lifeSpanHandler = SimBriefingPage.BrowserLifeSpanHandler(self)
     2230        self._browser.SetClientHandler(lifeSpanHandler)
     2231
     2232    def _invalidateBrowser(self):
     2233        """Invalidate the browser (and associated stuff)."""
     2234        self._alignment.remove(self._container)
     2235        self._container = None
     2236        self._browser = None
     2237
     2238#-----------------------------------------------------------------------------
     2239
    14272240class FuelTank(gtk.VBox):
    14282241    """Widget for the fuel tank."""
     
    16602473            self._wizard.gui.beginBusy(xstr("fuel_pump_busy"))
    16612474            self._pump()
     2475        elif self._wizard.usingSimBrief:
     2476            self._wizard.jumpPage(3)
    16622477        else:
    16632478            self._wizard.nextPage()
     
    17052520        if fuelTank is None:
    17062521            self._wizard.gui.endBusy()
    1707             self._wizard.nextPage()
     2522            if self._wizard.usingSimBrief:
     2523                self._wizard.gui.startMonitoring()
     2524                self._wizard.jumpPage(3)
     2525            else:
     2526                bookedFlight = self._wizard._bookedFlight
     2527                self._wizard.gui.beginBusy(xstr("route_down_notams"))
     2528                self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
     2529                                                      bookedFlight.departureICAO,
     2530                                                      bookedFlight.arrivalICAO)
     2531                startSound(const.SOUND_NOTAM)
    17082532        else:
    17092533            currentLevel = fuelTank.currentWeight / fuelTank.capacity
     
    17192543                                                      currentLevel)])
    17202544            gobject.timeout_add(50, self._pump)
    1721 
    1722 #-----------------------------------------------------------------------------
    1723 
    1724 class RoutePage(Page):
    1725     """The page containing the route and the flight level."""
    1726     def __init__(self, wizard):
    1727         """Construct the page."""
    1728         super(RoutePage, self).__init__(wizard, xstr("route_title"),
    1729                                         xstr("route_help"),
    1730                                         completedHelp = xstr("route_chelp"))
    1731 
    1732         alignment = gtk.Alignment(xalign = 0.5, yalign = 0.5,
    1733                                   xscale = 0.0, yscale = 0.0)
    1734 
    1735         mainBox = gtk.VBox()
    1736         alignment.add(mainBox)
    1737         self.setMainWidget(alignment)
    1738 
    1739         levelBox = gtk.HBox()
    1740 
    1741         label = gtk.Label(xstr("route_level"))
    1742         label.set_use_underline(True)
    1743         levelBox.pack_start(label, True, True, 0)
    1744 
    1745         self._cruiseLevel = gtk.SpinButton()
    1746         self._cruiseLevel.set_increments(step = 10, page = 100)
    1747         self._cruiseLevel.set_range(min = 0, max = 500)
    1748         self._cruiseLevel.set_tooltip_text(xstr("route_level_tooltip"))
    1749         self._cruiseLevel.set_numeric(True)
    1750         self._cruiseLevel.connect("changed", self._cruiseLevelChanged)
    1751         self._cruiseLevel.connect("value-changed", self._cruiseLevelChanged)
    1752         label.set_mnemonic_widget(self._cruiseLevel)
    1753 
    1754         levelBox.pack_start(self._cruiseLevel, False, False, 8)
    1755 
    1756         alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
    1757                                   xscale = 0.0, yscale = 0.0)
    1758         alignment.add(levelBox)
    1759 
    1760         mainBox.pack_start(alignment, False, False, 0)
    1761 
    1762 
    1763         routeBox = gtk.VBox()
    1764 
    1765         alignment = gtk.Alignment(xalign = 0.0, yalign = 0.5,
    1766                                   xscale = 0.0, yscale = 0.0)
    1767         label = gtk.Label(xstr("route_route"))
    1768         label.set_use_underline(True)
    1769         alignment.add(label)
    1770         routeBox.pack_start(alignment, True, True, 0)
    1771 
    1772         routeWindow = gtk.ScrolledWindow()
    1773         routeWindow.set_size_request(400, 80)
    1774         routeWindow.set_shadow_type(gtk.ShadowType.IN if pygobject
    1775                                     else gtk.SHADOW_IN)
    1776         routeWindow.set_policy(gtk.PolicyType.AUTOMATIC if pygobject
    1777                                else gtk.POLICY_AUTOMATIC,
    1778                                gtk.PolicyType.AUTOMATIC if pygobject
    1779                                else gtk.POLICY_AUTOMATIC)
    1780 
    1781         self._uppercasingRoute = False
    1782 
    1783         self._route = gtk.TextView()
    1784         self._route.set_tooltip_text(xstr("route_route_tooltip"))
    1785         self._route.set_wrap_mode(WRAP_WORD)
    1786         self._route.get_buffer().connect("changed", self._routeChanged)
    1787         self._route.get_buffer().connect_after("insert-text", self._routeInserted)
    1788         routeWindow.add(self._route)
    1789 
    1790         label.set_mnemonic_widget(self._route)
    1791         routeBox.pack_start(routeWindow, True, True, 0)
    1792 
    1793         mainBox.pack_start(routeBox, True, True, 8)
    1794 
    1795         self.addCancelFlightButton()
    1796 
    1797         self._backButton = self.addPreviousButton(clicked = self._backClicked)
    1798         self._button = self.addNextButton(clicked = self._forwardClicked)
    1799 
    1800     @property
    1801     def filedCruiseLevel(self):
    1802         """Get the filed cruise level."""
    1803         return self._cruiseLevel.get_value_as_int()
    1804 
    1805     @property
    1806     def route(self):
    1807         """Get the route."""
    1808         return self._getRoute()
    1809 
    1810     def activate(self):
    1811         """Setup the route from the booked flight."""
    1812         self._cruiseLevel.set_value(0)
    1813         self._cruiseLevel.set_text("")
    1814         self._route.get_buffer().set_text(self._wizard._bookedFlight.route)
    1815         self._updateForwardButton()
    1816 
    1817     def _getRoute(self):
    1818         """Get the text of the route."""
    1819         buffer = self._route.get_buffer()
    1820         return buffer.get_text(buffer.get_start_iter(),
    1821                                buffer.get_end_iter(), True)
    1822 
    1823     def _updateForwardButton(self):
    1824         """Update the sensitivity of the forward button."""
    1825         cruiseLevelText = self._cruiseLevel.get_text()
    1826         cruiseLevel = int(cruiseLevelText) if cruiseLevelText else 0
    1827         self._button.set_sensitive(cruiseLevel>=50 and self._getRoute()!="")
    1828 
    1829     def _cruiseLevelChanged(self, *arg):
    1830         """Called when the cruise level has changed."""
    1831         self._updateForwardButton()
    1832 
    1833     def _routeChanged(self, textBuffer):
    1834         """Called when the route has changed."""
    1835         if not self._uppercasingRoute:
    1836             self._updateForwardButton()
    1837 
    1838     def _routeInserted(self, textBuffer, iter, text, length):
    1839         """Called when new characters are inserted into the route.
    1840 
    1841         It uppercases all characters."""
    1842         if not self._uppercasingRoute:
    1843             self._uppercasingRoute = True
    1844 
    1845             iter1 = iter.copy()
    1846             iter1.backward_chars(length)
    1847             textBuffer.delete(iter, iter1)
    1848 
    1849             textBuffer.insert(iter, text.upper())
    1850 
    1851             self._uppercasingRoute = False
    1852 
    1853     def _backClicked(self, button):
    1854         """Called when the Back button is pressed."""
    1855         self.goBack()
    1856 
    1857     def _forwardClicked(self, button):
    1858         """Called when the Forward button is clicked."""
    1859         if self._completed:
    1860             self._wizard.nextPage()
    1861         else:
    1862             bookedFlight = self._wizard._bookedFlight
    1863             self._wizard.gui.beginBusy(xstr("route_down_notams"))
    1864             self._wizard.gui.webHandler.getNOTAMs(self._notamsCallback,
    1865                                                   bookedFlight.departureICAO,
    1866                                                   bookedFlight.arrivalICAO)
    1867             startSound(const.SOUND_NOTAM)
    18682545
    18692546    def _notamsCallback(self, returned, result):
     
    23383015        self._updatingMETAR = False
    23393016
    2340         self._runway.set_text("")
     3017        if self._wizard.takeoffRunway is None:
     3018            self._runway.set_text("")
     3019        else:
     3020            self._runway.set_text(self._wizard.takeoffRunway)
    23413021        self._runway.set_sensitive(True)
    23423022        self._sid.set_active(0)
     
    28973577        self._transition.set_sensitive(True)
    28983578
    2899         self._runway.set_text("")
     3579        if self._wizard.landingRunway is None:
     3580            self._runway.set_text("")
     3581        else:
     3582            self._runway.set_text(self._wizard.landingRunway)
    29003583        self._runway.set_sensitive(True)
    29013584
     
    35784261        self._payloadIndex = len(self._pages)
    35794262        self._pages.append(TimePage(self))
    3580         self._pages.append(FuelPage(self))
    35814263        self._routePage = RoutePage(self)
    35824264        self._pages.append(self._routePage)
     4265        self._simBriefSetupPage = SimBriefSetupPage(self)
     4266        self._pages.append(self._simBriefSetupPage)
     4267        self._simBriefingPage = SimBriefingPage(self)
     4268        self._pages.append(self._simBriefingPage)
     4269        self._pages.append(FuelPage(self))
    35834270        self._departureBriefingPage = BriefingPage(self, True)
    35844271        self._pages.append(self._departureBriefingPage)
     
    36534340        return self._loginResult
    36544341
    3655     def setCurrentPage(self, index, finalize = False):
    3656         """Set the current page to the one with the given index."""
     4342    def setCurrentPage(self, index, finalize = False, fromPageShift = None):
     4343        """Set the current page to the one with the given index.
     4344
     4345        @param fromPageShift if given, the relative index of one of the
     4346        previous pages that should be used as the from-page of the next
     4347        page. E.g. if fromPageShift is 1, the previous page will be the
     4348        from-page."""
    36574349        assert index < len(self._pages)
    36584350
     
    36634355                page.complete()
    36644356            self.remove(page)
     4357            if fromPageShift is not None:
     4358                fromPage -= fromPageShift
    36654359
    36664360        self._currentPage = index
     
    37414435
    37424436    @property
     4437    def alternate(self):
     4438        """Get the ICAO code of the alternate airport."""
     4439        return self._routePage.alternate
     4440
     4441    @property
    37434442    def departureMETAR(self):
    37444443        """Get the METAR of the departure airport."""
     
    38404539        return self._finishPage.online
    38414540
     4541    @property
     4542    def usingSimBrief(self):
     4543        """Indicate if we are using a SimBrief briefing or not."""
     4544        return self._usingSimBrief
     4545
     4546    @usingSimBrief.setter
     4547    def usingSimBrief(self, x):
     4548        """Set whether we are using a SimBrief briefing or not."""
     4549        self._usingSimBrief = x
     4550
    38424551    def nextPage(self, finalize = True):
    38434552        """Go to the next page."""
    38444553        self.jumpPage(1, finalize)
    38454554
    3846     def jumpPage(self, count, finalize = True):
     4555    def jumpPage(self, count, finalize = True, fromPageShift = None):
    38474556        """Go to the page which is 'count' pages after the current one."""
    3848         self.setCurrentPage(self._currentPage + count, finalize = finalize)
     4557        self.setCurrentPage(self._currentPage + count,
     4558                            finalize = finalize, fromPageShift = fromPageShift)
    38494559
    38504560    def grabDefault(self):
     
    38954605        self._arrivalNOTAMs = None
    38964606        self._arrivalMETAR = None
     4607        self._usingSimBrief = None
     4608        self.takeoffRunway = None
     4609        self.landingRunway = None
    38974610
    38984611        firstPage = 0 if self._loginResult is None else 1
     
    39384651        metar = metar.upper()
    39394652        if originator in [self._departureBriefingPage, self._takeoffPage]:
    3940             self._departureMETARChanged(metar, originator)
     4653            self.departureMETARChanged(metar, originator)
    39414654        else:
    3942             self._arrivalMETARChanged(metar, originator)
    3943 
    3944     def _departureMETARChanged(self, metar, originator):
     4655            self.arrivalMETARChanged(metar, originator)
     4656
     4657    def departureMETARChanged(self, metar, originator):
    39454658        """Called when the departure METAR has been edited on one of the
    39464659        pages.
     
    39524665                page.changeMETAR(metar)
    39534666
    3954     def _arrivalMETARChanged(self, metar, originator):
     4667    def arrivalMETARChanged(self, metar, originator):
    39554668        """Called when the arrival METAR has been edited on one of the
    39564669        pages.
Note: See TracChangeset for help on using the changeset viewer.